home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / Tool Chest / OS⁄Toolbox / Apple Events / AE & Scripting Dev Kit / AE Sample Applications / Quill 1.0d1 / Quill Code / Quill.p < prev    next >
Encoding:
Text File  |  1992-03-05  |  424.5 KB  |  12,425 lines  |  [TEXT/MPS ]

  1. {------------------------------------------------------------------------------
  2. #
  3. #    Quill
  4. #
  5. #    Apple Macintosh User Programming Group
  6. #
  7. #    MultiFinder-Aware, AppleEvents-Aware Simple Styled TextEdit Sample Application
  8. #
  9. #    by Bennet Marks
  10. #
  11. #    Copyright © 1991 Apple Computer, Inc.
  12. #
  13. #    Quill based on TEStyleSample  (Copyright © 1989 Apple Computer, Inc.)
  14. #
  15. #
  16. #    Quill.p    -    Pascal Source
  17. #
  18. #    All rights reserved.
  19. #
  20. #    Versions:    1.0                        02/18/91
  21. #
  22. #    Components:    Quill.p
  23. #                QuillGlue.a
  24. #                Quill.r
  25. #                Quill.h    
  26. #                Quill.make
  27. #
  28. #    Quill is an example application that demonstrates the use
  29. #    of the AppleEvent Manager in an application.  It responds to a variety
  30. #    of AppleEvents, including the Required AppleEvents (Open Application,
  31. #    Quit Application, Open Documents, and Print Documents); it supports
  32. #    the AppleEvents Object Model; and it is "factored", in the sense that
  33. #    user actions (choosing a menu item, dragging a window, etc.) are translated
  34. #    into AppleEvents that the application sends to itself, and then responds
  35. #    to in much the way that it would respond to such events from an outside 
  36. #    source.  Factoring your application is a way to make sure that all its
  37. #    functionality (or at least as much as you want) is available through 
  38. #    AppleEvents.  It also makes it easier to "record" user actions in the
  39. #    form of AppleEvents.
  40. #
  41. #    Quill is based on the sample application TEStyleSample, available
  42. #    from Apple Computer.  TEStyleSample was designed to demonstrate how 
  43. #    to initialize the commonly used toolbox managers, operate successfully 
  44. #    under MultiFinder, handle desk accessories and create, grow, and zoom windows.
  45. #    Both styled and fundamental TextEdit toolbox calls and TextEdit autoscroll 
  46. #    are demonstrated. It also shows how to create and maintain scrollbar controls 
  47. #    as well as implementing a basic printing loop.
  48. #
  49. #    In creating Quill, we have added in a number of application features
  50. #    NOT found in TEStyleSample, including multiple windows, saving documents and 
  51. #    opeining saved documents, and the like.  This was necessary to demonstrate how
  52. #    to access these features from AppleEvents, but may come in handy in any case.
  53. #    These added features are one of the reasons that Quill is a good deal
  54. #    larger than TEStyleSample.  Some of the extra code is present to implement
  55. #    AppleEvent awareness, but a lot of it just handles the normal tasks that any
  56. #    real application has to deal with.  Don't be so worried.
  57. #
  58. #    However, this application is an example of the form of an AppleEvent-aware
  59. #    application; it is not a template.  There's a lot more a real application
  60. #    has to do, and much of it won't be demonstrated here.
  61. #
  62. #    Quill is also a living document.  We're still learning the best way
  63. #    to do things with AppleEvents; and we're keeping one eye on the Open
  64. #   Scripting Architecture and possible future scripting languages at
  65. #    all times.
  66. #
  67. #    Other sample apps you may want to look at are: TEStyleSample; TESample, a simpler
  68. #    version of TEStyleSample without the styles; and Sample, a simple sample app
  69. #    that doesn't use TextEdit or the Control Manager.
  70. #
  71. ------------------------------------------------------------------------------}
  72.  
  73. {------------------------------------------------------------------------------
  74.  
  75.  HOW TO LOOK AT Quill:  the routines are broken into two large groups.
  76.  The first group are taken from TEStyleSample.  Any major changes made for 
  77.  Quill are noted.  The second group, starting from "NEW ROUTINES FOR
  78.  QUILL", are, naturally, new routines for Quill.  Some are
  79.  completely new (including all the AppleEvents-specific routines), while others
  80.  are major rewrites of old TEStyleSample routines (with new names), altered for 
  81.  AppleEvent awareness, more functionality, and more robustness.  Sounds like coffee, 
  82.  doesn't it?
  83.  
  84.  IMPORTANT NOTE ON FACTORING AND OTHER DESIGN ISSUES:  this sample program
  85.  illustrates several techniques for dealing with and making use of AppleEvents.
  86.  It is by no means the final word on the subject, and will probably evolve 
  87.  considerably.  One example concerns "factoring" - that is, separating the user
  88.  interface from the rest of the program, and designing the program so that user
  89.  actions are translated into AppleEvents which the program then sends to itself.
  90.  This is a useful strategy for making sure the full functionality of the program
  91.  is available through AppleEvents, and it assists in the "recording" of user actions.
  92.  
  93.  In most cases I've taken each user action and translated it into a single, 
  94.  indivisible AppleEvent.  For example, when the user chooses "Close" from the
  95.  File Menu, the program may query her on whether to save or not, and if so to
  96.  what file.  It then takes all the information - what window to close, save/don't save,
  97.  choice of file - attaches them to the Close event as parameters, and sends off
  98.  the Close Event.
  99.  
  100.  THIS IS NOT THE ONLY "RIGHT" WAY TO DO THIS!  You could, instead, query the
  101.  user and then, if necessary, send TWO events - first the Save, then the Close.
  102.  In this case the Close wouldn't be carrying around all those parameters.
  103.  
  104.  These design considerations will also affect what elements of the user interface
  105.  would be included down in the event handlers.  As a rule, it's best to design
  106.  the event handlers so that they can operate without any user actions.  After
  107.  all, when AppleEvents are being used to run your program from a remote location, 
  108.  or a script, there may be no user available to respond.
  109.  
  110.  We will probably have more sample code to illustrate these different approaches
  111.  in the future.
  112.  
  113.  A NOTE ON "GOTO'S":  some purists may be surprised to see frequent use of GOTO
  114.  in this code.  Further examination, however, will reveal that in almost every
  115.  case the only use of GOTO is in the form of GOTO 9, where 9 labels the location
  116.  of the routine's clean-up code, where data structures are de-allocated, the function
  117.  value is assigned, etc.  If a serious error occurs, we jump to 9 to handle the
  118.  clean-up; otherwise we just flow into it at the end of the routine.
  119.  
  120.  This is cleanly structured programming, despite the presence of the oft-dispised
  121.  GOTO.  In Pascal, the only alternative would be for each routine to have a
  122.  CleanUp subroutine contained within it, to be called in place of each GOTO 9
  123.  and at the end of the routine.  Compared to the GOTO's, that's ugly, confusing,
  124.  and (with our current compiler) generates very bad compiled code.  Enough said?
  125.  
  126. ------------------------------------------------------------------------------}
  127.  
  128. {------------------------------------------------------------------------------ 
  129.  
  130.     MODIFICATION HISTORY
  131.     
  132.     02/18/91    BHM        New today
  133.     04/19/91    BHM        Posted 1.00d2
  134.     04/22/91    BHM        Added PropFromNullAccessor, CoerceObjToProp; typeMyProp;
  135.                         PropToken
  136.     05/14/91    BHM        Added WordFromWndwAccessor, MyGetWord, ScanToBreak, ScanToNonBreak
  137.     05/15/91    BHM        Added CoerceObjToText, GetTextProp
  138.     05/16/91    BHM        (1) Introduced QuietCatchErr
  139.                         (2) Replaced CoerceObjToWndw, CoerceObjToProp, and
  140.                             CoerceObjToText with CoerceObjToAnything (pretty
  141.                             nifty, huh?)
  142.     05/20/91(!)    BHM        (1) Added CharFromWndwAccessor
  143.     05/21/91    BHM        (1) Added MyGetTextElem, ScanToDelimiter, TextElemFromWndwAccessor
  144.     05/22/91    BHM        **IMPORTANT** - switched to new file, NewAEQuillSample.p,
  145.                         to make text token changes and some OSL adjustments.  
  146.                         AEQuillSample. still exists, plus a safety copy AEQuillSample.p.5.22
  147.     05/23/91    BHM        Transferred over NewAEQuillSample.p, including all the changes in
  148.                         the text tokens, back to AEQuillSample.p, which lives again
  149.     05/24/91    BHM        Added MakeStylTextDesc, CoerceStylTextToText
  150.     05/29/91    BHM        Added GetTextElemFromText, MakeTextTokenForWndw, InitTextToken,
  151.                         TextElemFromTextAccessor, TextElemFromWndwAccessor; dropped
  152.                         CharFromWndwAccessor, WordFromWndwAccessor
  153.     05/31/91    BHM        added "Quit NOW" menu command
  154.     06/03/91    BHM        Started change-over to use of prop tokens; pre-change version
  155.                         saved as AEQuillSample.p.6.3
  156.     06/05/91    BHM        Added MySetData, MyGetDataDesc, SetStylTextData, GetStylTextData,
  157.                         SetPropForWndwDesc, GetPropForWndwDesc.  We now use prop tokens.
  158.     06/07/91    BHM        Added CountWords, CountDelChars, CountTextElems
  159.     06/18/91    BHM        over the last few days . . .
  160.                         (1) added GetPropForTextDesc, CoerceFontToInt, SetPropForText
  161.                         (2) added PropFromTextAccessor, MyGetUniformStyles, GetStyleFromConstant,
  162.                         MyAEListToStyles, InitTheStyles, StylesToAEList
  163.     06/21/91    BHM        Added CoerceMyTextToStylText
  164.     07/01/91    BHM        (1) Added lots of routines:  SetUpEdit, DoMenuEdit, DoMenuStyle, HandleCopy,
  165.                         HandleCut, HandlePaste, MakeSelTextObj, SetFontForSelText, SetSizeForSelText,
  166.                         SetStyleForSelText, SelectTextToken, MyDoCut, MyDoPaste, MyDoCopy  - and 
  167.                         maybe a few more.
  168.                         (2) Also added new text element: "spots" (0-length strings)
  169.     07/09/91    BHM        Added RealCountProc, HandleNumberOfElements
  170.     07/10/91    BHM        (1) Added things for new ShowAllErrs property, including:
  171.                         globals gShowAllErrs, gInHandler; mathoms menu; routines
  172.                         PreHandler, PostHandler, SetPropForApp, GetPropForApp,
  173.                         DoMenuMathoms, PropFromAppAccessor
  174.                         (2) Improved the font stuff with: CoerceMyFontToText, CoerceMyFontToInt,
  175.                         CoerceMyFontToOldFont, CoerceTextToMyFont, CoerceIntToMyFont
  176.     07/15/91    BHM        FIRST PROTOTYPE RELEASE
  177.     07/22/91    BHM        Implemented dirty-window checking, with DirtyWindow, CleanWindow,
  178.                         WindowIsDirty
  179.     07/31/91    BHM        (1) Put in code to handle window-switching as AppleEvents: BackWindow,
  180.                         HandleMove, MySendWindow, SendAEMove, MyBringWndwFront
  181.                         (2) Implemented recording of user typing actions: MyAEDoKey, StartKeyBuffering,
  182.                         ContinueKeyBuffering, CheckKeyBuffer, ResetKeyBuffer, InitKeyBufVals, InitKeyBuffer,
  183.                         GrowKeyBuffer, DestroyKeyBuffer, MakeTextRangeObj, MakeSpotObj - as well as new types
  184.                         (e.g. KeyBufferRecord), globals (keyBuffer), and constants to go with them
  185.                         (3) Took error dialog out of DoHighLevelEvent (so we don't complain when we get an
  186.                         AppleEvent we don't have a handler for; we just drop it)
  187.     08/02/91    BHM        Put in support for text "style item" plain (including MakePlainList) - 
  188.                         **CHECK - this should be cleaned up
  189.     08/05/91    BHM        SECOND PROTOTYPE RELEASE
  190.     08/13/91    BHM        Put in improved support for the formAbsoluteOrdinal naming form, making use
  191.                         of ordinary integers (positive or negative) and "magic ordinals" (first, last,
  192.                         any, middle, all).  Routines:  DecodeOrdinal (very handy), MakeWindowList,
  193.                         MyRandom, MakeElemList
  194.     08/18/91    BHM        Put in support for some list handling, so the GetData and SetData can work
  195.                         with the lists of tokens that the OSL can produce.  Routines:  SetListData,   
  196.                         GetListData, PropFromListAccessor
  197.     08/21/91    BHM        (1) Replaced PropFromListAccessor with AnythingFromListAccessor (so we can get
  198.                         elements or properties from lists, returning lists as a result)
  199.                         (2) Put in new class: cListElem, which represents the elements in a list.  Added
  200.                         ElemFromAnythingAccessor, and some code to MyCountProc, to handle them.
  201.     08/22/91    BHM        (1) Put in pLength and pOffset for text tokens
  202.                         (2) Put in Kurt's Comparison routines (AECompareLib, and changes to MyCompareProc) 
  203.     08/23/91    BHM        THIRD PROTOTYPE RELEASE
  204.     08/26/91    BHM        Added CoerceMyDocToMyWndw, other changes to handle and use cDocument (nearly identical
  205.                         in behavior to cWindow)
  206.     09/06/91    BHM        Added HandleDeleteElement, with support routines:  ExtendWord, ExtendTextElem, DeleteThisText,
  207.                         DeleteThisObj (all of which needs a lot more testing)
  208.     09/09/91    BHM        Removed a lot of robustness checks from my accessors (particularly checks
  209.                         on containerClass) - they were starting to get in the way
  210.     09/16/91    BHM        (1) Made some changes to handle token lists better: rewrote HandleGetData;
  211.                         added GetDataFromToken, GetDataFromTokenList; threw away GetListData,
  212.                         MyGetDataDesc
  213.                         (2) While I was at it, renamed GetPropForApp (now GetDataFromAppProp),
  214.                         GetPropForTextDesc (now GetDataFromTextProp), GetPropForWndwDesc (now
  215.                         GetDataFromWndwProp) - sounded better
  216.                         (3) Fonts are now of typeText and nothing else; there is no more typeFont,
  217.                         typeMyFont, or whatever.  All the coercions for fonts have gone away.
  218.     09/18/91    BHM        (1) Rewrote HandleSetData so that it would deal with lists better and allow
  219.                         the data to be specified by an object.  Added SetDataForToken, SetDataForTokenList,
  220.                         GetSingularData; dropped MySetData, SetListData
  221.                         (2) Renamed SetPropForWndwDesc (now SetDataForWndwProp), SetPropForText (now 
  222.                         SetDataForTextProp), SetPropForApp (now SetDataForAppProp)
  223.                         (3) Added code to return an error object descriptor to the caller when my use of 
  224.                         the OSL results in an error.  The major changes are in PostHandler.  Also needed:
  225.                         global VAR gErrorDesc and new routine MyGetErrorDesc (a callback for the OSL).
  226.     10/04/91    BHM        10-4, Good Buddy!  Put in "smart recording" of text operations - can now record
  227.                         "cut word 3" rather than "cut characters 14 to 19".  New routines: SmartMakeSelTextObj,
  228.                         SmartTokenRep
  229.     12/11/91    BHM        (1) Started changes for new Registry:  proper use of kCoreEventClass (the 4 Required Events),
  230.                         kAECoreSuite (the Core Suite).  Also corrected pName constant.
  231.                         (2)  CHANGED NAME OF PROGRAM TO QUILL.
  232.     12/16/91    BHM        (1) Changed HandleClose to:  resolve direct obj directly (rather than in a coercion handler;
  233.                         work with lists of objects; handle kAEAsk option.
  234.                         (2) Changed all kAEAskUser ('asku') constants to kAEAsk ('ask ') to match new Registry.
  235.                         (3) Changed MyAECoerceDescPtr to handle typeWildCard properly (and to avoid unnecessary
  236.                         duplicating.
  237.     12/18/91    BHM        Changed HandleMove to: resolve direct obj directly; handle lists; work with insertion locs.
  238.                         (And changed MyBringWndwFront to match.)
  239.     01/08/92    BHM        Happy New Year!  Implemented the new Registry version of text styles, using the typeTextStyles
  240.                         data type.  This involved changes to SetDataForTextProp, GetDataFromTextProp, and InitTheStyles,
  241.                         and the addition of several new routines:  StyleDescToStyleSets, ListToStyleSet, 
  242.                         GetStyleItemFromConst, StyleSetToList, StyleSetsToStyleDesc, CoerceListOrValToTextStyles, 
  243.                         SmartMakeStyleData (some of which replace previous routines).  We now handle two text style
  244.                         properties:  pTextStyles and pUniformStyles.
  245.     01/20/92    BHM        Added AERegistry to USES, started integrating new constants, including:         
  246.                         (1) Changed typeText to typeChar everywhere
  247.                         (2) Changed NumberOfElements to CountElements (in routine names, constants, etc.)
  248.                         (3) Changed typeRangeDataDescriptor to typeRangeDescriptor (**CHECK - how did that EVER work?)
  249.                         (4)    Dropped SendAEMove (wasn't being used, didn't work with insertion locs - we use
  250.                         MyBringWndwFront instead)
  251.     01/21/92    BHM        Replaced HandleNewElement with HandleCreateElement.  Related to that:  dropped SendAENewElement,
  252.                         rewrote DoMenuNew, fixed a bug in MySendWindow.
  253.     01/27/92    BHM        (1) Put in code for typeIntlText (the default type for many text objects) - including
  254.                         CoerceStylTextToIntlText, CoerceIntlTextToText, CoerceTextToIntlText, TextToIntlText, 
  255.                         IntlTextToText (there's a certain amount of overlap there).
  256.                         (2) HandleGetData now takes a list of requested types (instead of just one), and also
  257.                         deals with typeBest.  Related: changes to GetDataFromTokenList, GetDataFromToken.
  258.                         New routines:  GetWildTypes, MatchToReqList.
  259.                         (3) Changed event class on Cut, Copy, & Paste from kAECoreSuite to kAEMiscStandards
  260.     01/29/92    BHM        (1) Rewrote HandlePrintDocs (now just HandlePrint) to handle obj specs that reolve to
  261.                         lists, and to get the interaction rules right.  New routines: PrintFile (replacing 
  262.                         MyPrintFile), PrintFileList, PrintToken (basically replacing MyPrintWindow), PrintTokenList,
  263.                         NewPrintText (replacing PrintText).  New globals: gInterMode, gTriedDialog.
  264.     01/31/92    BHM        (1) Rewrote HandleCopy, HandleCut, HandlePaste to match latest Registry (no parameters,
  265.                         always act on current selection); also DoMenuEdit.  Dropped MyDoCopy, MyDoCut, MyDoPaste,
  266.                         SetUpEdit.
  267.                         (2) Added some window/document properties: pVisible, pIndex, pIsModal, pIsResizable,
  268.                         pHasTitleBar, pIsModified (note that I've extended all window props to documents and
  269.                         vice-versa)
  270.                         (3) Added HandleDoObjectsExist (an easy one)
  271.     02/13/92    BHM        (1) Changed some constants that were peculiar to Quill - typeStylText, keyAETheStylInfo,
  272.                         typeStylInfo, keyAETheText - to their new, improved Registry-defined versions (from
  273.                         the Misc Standards) - typeStyledText, keyAEStyles, typeScrapStyles, keyAEText.  Respectively.
  274.                         (2) Cleaned up a bug in SmartTokenRep (I was unlocking a potentially non-existent handle)
  275.     02/17/92    BHM        (1) Added pUserSelection (app property) (also added MakeSelTextToken for it, a routine that should
  276.                         be used elsewhere as well - **CHECK)
  277.                         (2) Replaced pText with pContents (window property - all the text in the window), and made changes
  278.                         so that it works right - will now return same types as any other text object (not just typeChar)
  279.                         (3) Re-wrote TextTokenToDesc to eliminate silly dependencies; the new version is based on something
  280.                         once called GetTextProp (but which never did anything but get the text from a token; back then we 
  281.                         didn't have any other text properties), which it replaces throughout (meaning, in MakeStylTextDesc)
  282.                         (4)  Made an EXPERIMENTAL change wherein the pContents property of windows/docs is returned as
  283.                         a text token (rather than a window prop token), in order to net us all the text properties/behaviors
  284.                         for free.  Gearing up to do the same for pUserSelection, although that's a little more complicated
  285.                         (**CHECK)
  286.     02/19/92    BHM        (1) Fixed bug in GetDataFromTextProp (pTextStyles case) that was skipping over the offStyles
  287.                         (2) Replaced kAECondense with kAECondensed, kAEExtend with kAEExpanded (constants representing
  288.                         text style items; I had been using my own for those two, but they're in the Registry)
  289.     02/21/92    BHM        Restored optional text object parameters to Cut, Copy, and Paste events so that they'll record
  290.                         better.  This involved bringing back SetUpEdit, MyDoCut, MyDoCopy, and MyDoPaste; changes to 
  291.                         the three event handlers; and some other minor alterations
  292.                         
  293.     
  294.     END OF HISTORY
  295.     
  296. ------------------------------------------------------------------------------}
  297.  
  298. PROGRAM Quill;
  299.  
  300. {Segmentation strategy:
  301.  
  302.  This program consists of three segments. Main contains most of the code,
  303.  including the MPW libraries, and the main program. Initialize contains
  304.  code that is only used once, during startup, and can be unloaded after the
  305.  program starts. %A5Init is automatically created by the Linker to initialize
  306.  globals for the MPW libraries and is unloaded right away.}
  307.  
  308.  
  309. {SetPort strategy:
  310.  
  311.  Toolbox routines do not change the current port. In spite of this, in this
  312.  program we use a strategy of calling SetPort whenever we want to draw or
  313.  make calls which depend on the current port. This makes us less vulnerable
  314.  to bugs in other software which might alter the current port (such as the
  315.  bug (feature?) in many desk accessories which change the port on OpenDeskAcc).
  316.  Hopefully, this also makes the routines from this program more self-contained,
  317.  since they don't depend on the current port setting.}
  318.  
  319.  
  320. {Clipboard strategy: 
  321.  
  322.  Under styled TextEdit, TECut and TECopy will write both the text and associated
  323.  style information directly to the desk scrap as types 'TEXT' and 'styl'.
  324.  Instead of using TEToScrap and TEFromScrap, a new routine TEStylPaste, will 
  325.  transfer the text and style from the desk scrap to the document. }
  326.  
  327.  {Error-handling strategy (NEW FOR QUILL):
  328.  
  329.  All AppleEvent Manager routines are functions that return an error code.  In
  330.  keeping with this philosophy, most of the new routines in Quill also
  331.  return error codes.  Error-handling is done in a very general way, designed for
  332.  clarity and ease of debugging - NOT for true user-oriented error-handling.
  333.  
  334.  Every place in the code where a serious error may occur (one that would require
  335.  aborting some activity and/or informing the user) there is a call to one of the
  336.  three slightly different error-checking routines:  CatchErr, CheckErr, and DoMyErr.
  337.  Right now all 3 are set up to display a dialog window giving the error number
  338.  and the place in the code where it occurred (some unique number supplied by the 
  339.  programmer), and then return to the program.  They could just as easily be set up
  340.  to:  enter the debugger; write a string to a file; beep a tune; or whatever else
  341.  you want.  In a real application, you would want to do different things depending
  342.  on the location and nature of the error.  All routines are self-cleaning:  if an 
  343.  error occurs (and CatchErr et al return to the program after reporting it, as they do
  344.  now), the routine will dispose of structures it's created, unlock handles it's locked, 
  345.  etc., as appropriate.  In most cases it will also pass the error up the routine that
  346.  called it, so most serious errors will trigger a "chain" of dialog alerts as the
  347.  error gets passed up the calling chain.  Again, you can change this behavior in 
  348.  whichever way suits you.
  349.  
  350.  Most of my AppleEvent "Sends" do not ask for a reply, and thus they do not react
  351.  to any errors generated by the event handlers.  However, if you DO ask for a reply,
  352.  and a handler happens to generate an error, it will return the error code as part of
  353.  the reply - this is done automatically by the AE Manager.  (As currently written, the
  354.  handlers will NOT return an error string, which has to be done explicitly.)  In a real
  355.  application, most of the visible error-handling - alerting the user, for example -
  356.  would probably be done by the code that sends the events, not the handlers that receive
  357.  them.  }
  358.  
  359.  
  360.  
  361.  {$D+}
  362.  
  363. USES
  364.     MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, Traps, AppleEvents,
  365.     AEObjects, AECompareLib, MacPrint, AERegistry, Script, Language, OSUtils;
  366.  
  367. CONST
  368.  
  369.     {kTextMargin is the number of pixels we leave blank at the edge of the window.}
  370.     kTextMargin                = 2;
  371.  
  372.     {kMaxOpenDocuments is used to determine whether a new document can be opened
  373.      or created. We keep track of the number of open documents, and disable the
  374.      menu items that create a new document when the maximum is reached. If the
  375.      number of documents falls below the maximum, the items are enabled again.}
  376.     kMaxOpenDocuments        = 6;    { NEW FOR QUILL }
  377.     
  378.     {kMaxDocWidth is an arbitrary number used to specify the width of the TERec's
  379.     destination rectangle so that word wrap and horizontal scrolling can be
  380.     demonstrated.}
  381.     kMaxDocWidth            = 576;
  382.     
  383.     {kMinDocDim is used to limit the minimum dimension of a window when GrowWindow
  384.     is called.}
  385.     kMinDocDim                = 64;
  386.     
  387.     {kControlInvisible is used to 'turn off' controls (i.e., cause the control not
  388.     to be redrawn as a result of some Control Manager call such as SetCtlValue)
  389.     by being put into the contrlVis field of the record. kControlVisible is used
  390.     the same way to 'turn on' the control.}
  391.     kControlInvisible        = 0;
  392.     kControlVisible            = $FF;
  393.  
  394.     {kScrollBarAdjust and kScrollBarWidth are used in calculating
  395.     values for control positioning and sizing.}
  396.     kScrollbarWidth            = 16;
  397.     kScrollbarAdjust        = kScrollbarWidth - 1;
  398.  
  399.     {kScrollTweek compensates for off-by-one requirements of the scrollbars
  400.      to have borders coincide with the growbox.}
  401.     kScrollTweek            = 2;
  402.  
  403.     {kCrChar is used to match with a carriage return when calculating the
  404.     number of lines in the TextEdit record. kDelChar is used to check for
  405.     delete in keyDowns.}
  406.     kCRChar                    = 13;
  407.     kDelChar                = 8;
  408.  
  409.     {kButtonScroll is how many pixels to scroll horizontally when the button part
  410.     of the horizontal scrollbar is pressed.}
  411.     kButtonScroll            = 4;
  412.     
  413.     {kMaxTELength is an arbitrary number used to limit the length of text in the TERec
  414.     so that various errors won't occur from too many characters in the text.}
  415.     kMaxTELength            = 32000;
  416.     (* what about that tech note I wrote? is this a valid check anymore? maw *)
  417.  
  418.     {kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the
  419.      SysEnvRec we understand.}
  420.     kSysEnvironsVersion        = 1;
  421.  
  422.     {kOSEvent is the event number of the suspend/resume and mouse-moved events sent
  423.      by MultiFinder. Once we determine that an event is an osEvent, we look at the
  424.      high byte of the message sent to determine which kind it is. To differentiate
  425.      suspend and resume events we check the resumeMask bit.}
  426.     kOSEvent                = app4Evt;    { event used by MultiFinder }
  427.     kSuspendResumeMessage    = 1;        { high byte of suspend/resume event message }
  428.     kResumeMask                = 1;        { bit of message field for resume vs. suspend }
  429.     kMouseMovedMessage        = $FA;        { high byte of mouse-moved event message }
  430.     kNoEvents                = 0;        {no events mask}
  431.  
  432.     {kMinHeap - This is the minimum result from the following
  433.      equation:
  434.             
  435.             ORD(GetApplLimit) - ORD(ApplicZone)
  436.             
  437.      for the application to run. It will insure that enough memory will
  438.      be around for reasonable-sized scraps, FKEYs, etc. to exist with the
  439.      application, and still give the application some 'breathing room'.
  440.      To derive this number, we ran under a MultiFinder partition that was
  441.      our requested minimum size, as given in the 'SIZE' resource.}
  442.      
  443.     kMinHeap    = 29 * 1024; 
  444.  
  445.     {kMinSpace - This is the minimum result from PurgeSpace, when called
  446.      at initialization time, for the application to run. This number acts
  447.      as a double-check to insure that there really is enough memory for the
  448.      application to run, including what has been taken up already by
  449.      pre-loaded resources, the scrap, code, and other sundry memory blocks.}
  450.      
  451.     kMinSpace    = 20 * 1024;
  452.     
  453.     {kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions.}
  454.     kExtremeNeg        = -32768;
  455.     kExtremePos        = 32767 - 1;    { required for old region bug }
  456.     
  457.     {kTESlop provides some extra security when pre-flighting edit commands.}
  458.     kTESlop            = 1024;
  459.  
  460.     {kErrStrings is the resource ID for the error strings STR# resource.}
  461.     kErrStrings        = 128;
  462.     
  463.     kNumOfStyles    =    7;    { see InitTheStyles for the list }
  464.  
  465.     { The following are indicies into STR# resources. }
  466.     eWrongMachine    = 1;
  467.     eSmallSize        = 2;
  468.     eNoMemory        = 3;
  469.     eNoSpaceCut        = 4;
  470.     eNoCut            = 5;
  471.     eNoCopy            = 6;
  472.     eExceedPaste    = 7;
  473.     eNoSpacePaste    = 8;
  474.     eNoWindow        = 9;
  475.     eExceedChar        = 10;
  476.     eNoPaste        = 11;
  477.     eNoSelfAddr        = 12;    { NEW FOR QUILL }
  478.     
  479.     
  480.     { The following constants are all resource IDs, corresponding to their resources }
  481.     
  482.     rMenuBar    = 128;                { application's menu bar }
  483.     rAboutAlert    = 128;                { about alert }
  484.     rUserError    = 129;                { user error alert }
  485.     rUserAlert    = 130;                { user alert }
  486.     rYesOrNo    = 131;                { yes/no/cancel window }
  487.     rDocWindow    = 128;                { application's window }
  488.     
  489.     rVScroll    = 128;                { vertical scrollbar control }
  490.     rHScroll    = 129;                { horizontal scrollbar control }
  491.  
  492.  
  493.     { The following constants are all menu and item IDs corresponding to their resources }
  494.     
  495.     mApple        = 128;                { Apple menu }
  496.     iAbout        = 1;
  497.  
  498.     mFile        = 129;                { File menu }
  499.     iNew        = 1;
  500.     iOpen        = 2;
  501.     iClose        = 4;
  502.     iSave        = 5;                { NEW FOR QUILL }
  503.     iSaveAs        = 6;                { NEW FOR QUILL }
  504.     iRevert        = 7;                { NEW FOR QUILL }
  505.     
  506.     iPageSetup    = 9;                { NEW FOR QUILL }
  507.     iPrint        = 10;                { NEW FOR QUILL }
  508.     iPrintFile    = 11;                { NEW FOR QUILL }
  509.     iQuit        = 13;
  510.     iQuitNow    = 14;                { NEW FOR QUILLSAMPLE }
  511.  
  512.     mEdit        = 130;                { Edit menu }
  513.     iUndo        = 1;
  514.     iCut        = 3;
  515.     iCopy        = 4;
  516.     iPaste        = 5;
  517.     iClear        = 6;
  518.     iSelectAll    = 8;                { Added for TEStyleSample }
  519.     
  520.     mFont         = 131;                { Font menu-added for TEStyleSample }
  521.     
  522.     mFontSize     = 132;                { Font size menu-added for TEStyleSample }
  523.     iNine        = 1;
  524.     iTen        = 2;
  525.     iTwelve        = 3;
  526.     iFourteen    = 4;
  527.     iEighteen    = 5;
  528.     iTwoFour    = 6;
  529.     
  530.     mStyle         = 133;                { Style menu-added for TEStyleSample }
  531.     iPlain         = 1;
  532.     iBold         = 3;
  533.     iItalic        = 4;
  534.     iUnderline     = 5;
  535.     iOutline     = 6;
  536.     iShadow     = 7; 
  537.     
  538.     mMathoms        = 134;
  539.     iShowAllErrs    = 1;
  540.     
  541.     {kDITop and kDILeft are used to locate the Disk Initialization dialogs.}
  542.     kDITop        = $0050;
  543.     kDILeft        = $0070;
  544.     
  545.     
  546.     { the following constants re all NEW FOR QUILL }
  547.     
  548.     typeMyWndw    =    'BWIN';    { my private token type for windows }
  549.     typeMyDoc    =    'BDOC';
  550.     typeMyProp    =    'BPRP';    { my private token type for properties }
  551.     typeMyText  =    'BTXT';    { my private token type for text }
  552.     
  553.     typeMyWndwProp    =    'BWDP';    { later we may want to go to typeMyProp }
  554.     typeMyTextProp    =    'BTXP';
  555.     typeMyAppProp    =    'BAPR';
  556.         
  557.     badVRefNum =     $7FFF;    { no volume should ever get this vRefNum }
  558.     
  559.     
  560.     { these are temporary, while we decide what kind
  561.       of errors callbacks should return }
  562.     genericErr        =    -1799;
  563.     accessorErr        =    -1798;
  564.     countProcErr    =    -1797;
  565.     compareErr        =    -1796;
  566.      
  567.     errTooManyDocs    =    -1795;
  568.     errNoNewWindow    =    -1794;
  569.     errNoNewControl =    -1793;
  570.     errNoNewTE        =    -1792;
  571.     stylHndlErr        =    -1791;
  572.     
  573.     errAEUserCancelled = -1790;
  574.     
  575.     errAEBadData    =    -1789;
  576.     errCantPaste    =    -1788;
  577.     
  578.     errAENeedSingleItem    =    -1787;
  579.     
  580.     errAEMiscPrintErr    =    -1786;
  581.     
  582.     asciiSpace        =    $20;
  583.     asciiCR            =    $0D;
  584.     asciiComma        =    $2C;
  585.     
  586.     { codes for arrow keys }
  587.     kRightArrow        =    $1D;
  588.     kLeftArrow        =    $1C;
  589.     kUpArrow        =    $1E;
  590.     kDownArrow        =    $1F;
  591.     
  592.     kBufStartSize    =    64;
  593.     kBufGrowAmount    =    64;    
  594.         
  595.     
  596.     { these should come from the registry }
  597.     
  598. {    kAECoreSuite    =    'core';}
  599.     
  600.     
  601. {    cNull            =     typeNull;    }{ combine the redundancies  . . . }
  602. {    cWindow            =     'cwin';
  603.     typeText        =    'TEXT';
  604.     cText            =    typeChar;
  605.     pText            =    'TEXT';
  606.     cWord            =    'cwor';
  607.     
  608.     cDocument        =    'docu';
  609.     
  610.     cProperty        =    'prop';
  611.     
  612.     kAESetData        =    'setd';
  613.     keyAETheData    =    'kdat';
  614.     cQDRectangle    =    'qdrt';
  615.     typeQDRectangle    =    cQDRectangle;
  616.     pBounds            =    'pbnd';
  617.     pName            =    'pnam';
  618.     
  619.     pPosition        =    'ppos';
  620.     typeQDPoint        =    'QDpt';
  621.     cQDPoint        =    typeQDPoint;
  622.     
  623.     
  624.     keyAESaveOptions =     'savo';
  625.     kAEClose        =    'clos';
  626.     kAEYes            =    'yes ';
  627.     kAENo            =    'no  ';
  628.     kAEAsk            =    'ask ';
  629.     
  630.     keyAEObjToCreate =    'obtc';
  631.     kAENewElement    =    'nobj';
  632.     
  633.     keyAEDestination =     'dest';
  634.     
  635.     kAESave =             'save';
  636.     
  637.     kAEGetData    =        'getd';
  638.     
  639.     keyAERequestedType = 'rtyp';
  640.     
  641.     pVersion        =    'vers';
  642.     
  643.     cChar            =    'cha ';
  644.     cLine            =    'clin';
  645.     cItem            =    'citm';
  646.     cSpot            =    'cspt';
  647.     
  648.     cListElem        =    'celm';
  649.     
  650.     
  651.     
  652.     typeRangeDataDescriptor = 'rdd ';
  653.         
  654.     pPointSize                =    'ptsz';
  655.     typeFixed16                =    'fixd';
  656.     
  657.     pFont                    =    'font';
  658.     
  659.     pTextStyles                =    'txst';
  660.     pUniformStyles            =    'ustl';
  661.     
  662.     pLength                    =    'lgth';
  663.     pOffset                    =    'ofst';
  664.     
  665.   kAEBold            =    'bold';
  666.   kAENotBold        =    'nbld';
  667.   kAEItalic            =    'ital';
  668.   kAENotItalic        =    'nitl';
  669.   kAEUnderline        =    'ulin';
  670.   kAENotUnderline    =    'nuln';
  671.   kAEOutline        =    'olin';
  672.   kAENotOutline        =    'noln';
  673.   kAEShadow            =    'shdw';
  674.   kAENotShadow        =    'nsdw';
  675.   kAECondense        =    'cnds';
  676.   kAENotCondense    =    'ncnd';
  677.   kAEExtend            =    'xtnd';
  678.   kAENotExtend        =    'nxtn';
  679.   
  680.   kAEPlain            =    'plai';
  681.   
  682.   kAECut            =    'cut ';
  683.   kAEPaste            =    'past';
  684.   kAECopy            =    'copy';    }{ **CHECK - registry says something different (and weird) }
  685.   
  686. {  kAENumberOfElements        =    'nele';}
  687. {  keyAEWantClass            =    'want';}
  688. {  keyAEObjectClass            =    'kocl';
  689.   
  690.   pErrMode        =    'pemd';
  691.   kShowAllErrs    =    'sars';
  692.   kShowFewErrs    =    'sfrs';
  693.   
  694.   kAEMove        =    'move';
  695.   typeInsertionLoc    =    'insl';
  696.   
  697.   keyAEPosition    =    'kpos';
  698.   keyAEObject    =    'kobj';
  699.     
  700.   kAEBefore        =    'befo';
  701.   kAEAfter        =    'afte';
  702.   kAEReplace    =    'rplc';
  703.     
  704.   kAEBeginning    =    'bgng';
  705.   kAEEnd        =    'end ';
  706.   
  707.   keyAEInsertHere        =    'insr';
  708.   keyAEWhereModifier    =    'wher';
  709.   
  710.   kAEDontExecute    =    $2000;}    { use in SendMode, when you just want an event recorded, not executed }
  711.   
  712. {  kAEDelete            =    'delo';
  713.   
  714.   keyAEErrorObject    =    'erob';
  715.   
  716.   keyAEOnStyles        =    'onst';
  717.   keyAEOffStyles    =    'ofst';
  718.   typeTextStyles    =    'tsty';}
  719.   
  720.     cListElem        =    'celm';
  721.     
  722.     kAEDontExecute    =    $2000;
  723.     
  724.     
  725.     cSpot            =    'cspt';
  726.     
  727.     pErrMode        =    'pemd';
  728.     kShowAllErrs    =    'sars';
  729.     kShowFewErrs    =    'sfrs';
  730.     
  731.     pLength            =    'lgth';
  732.     pOffset            =    'ofst';
  733.     
  734.     pContents        =    'pcnt';
  735.     
  736.     pPosition        =    'ppos';
  737.     
  738.     
  739.     
  740.     { these next are for New Element - need to be replaced with Create Object }
  741.     keyAEObjToCreate    =    'obtc';
  742.     kAENewElement        =    'nobj';
  743.     
  744.     cNull            =    typeNull;
  745.     
  746.     { do we want/need these? }
  747.       kAECondense        =    'cnds';
  748.     kAEExtend        =    'xtnd';
  749.  
  750.       keyAEErrorObject    =    'erob';
  751.     
  752. { END OF CONSTANTS }
  753.     
  754.     
  755. TYPE
  756.     {A DocumentRecord contains the WindowRecord for one of our document windows,
  757.      as well as the TEHandle for the text we are editing. We have added fields to
  758.      hold the ControlHandles to the vertical and horizontal scrollbars and to hold
  759.      the address of the default clikLoop that gets attached to a TERec when you call
  760.      TEAutoView. Other document fields can be added to this record as needed. For
  761.      a similar example, see how the Window Manager and Dialog Manager add fields
  762.      after the GrafPort.}
  763.     DocumentRecord        = RECORD
  764.         docWindow:    WindowRecord;
  765.         docTE:        TEHandle;
  766.         docVScroll:    ControlHandle;
  767.         docHScroll:    ControlHandle;
  768.         docClik:    ProcPtr;
  769.         docFile:    FSSpec;        { NEW FOR QUILL; holds file spec for doc, if any }
  770.         dirtyFlag:    BOOLEAN;    { NEW FOR QUILL }
  771.     END;
  772.     DocumentPeek        = ^DocumentRecord;
  773.     
  774.     HandleList            = ARRAY[1..256] OF Handle;    { declared with 256 to beat range-checking }
  775.                                                     { local versions can be declared with less }
  776.     HandleListPtr        = ^HandleList;
  777.         
  778.     WndwPropToken    =
  779.       RECORD
  780.         wpWndw:    WindowPtr;
  781.         wpProp:    DescType;
  782.       END;
  783.                       
  784.     TextToken    =
  785.       RECORD
  786.         tokenClass:        DescType;    { cChar, cWord, cClass, or cLine } { or cSpot }
  787.         tokenWndw:        WindowPtr;
  788.         tokenOffset:    LongInt;    { offset from start of text to first character of token }
  789.         tokenLength:    LongInt;    { length of token }
  790.       END;
  791.       
  792.   { NOTES:  offsets start at 0; e.g., tokenOffset = 0 and tokenLength = 1
  793.               describes the first character of the text }
  794.             
  795.     TextPropToken    =
  796.       RECORD
  797.         tpText:    TextToken;
  798.         tpProp:    DescType;
  799.       END;
  800.       
  801.     StyleNameRec    =
  802.       RECORD
  803.         snStylItem:    StyleItem;
  804.         snName:        Str15;
  805.       END;
  806.       
  807.   MyStylItemRec    =    
  808.     RECORD
  809.       stylItem:        StyleItem;
  810.       stylConst:    DescType;
  811.     END;
  812.     
  813.     CharBuffer    =    PACKED ARRAY[0..kMaxTELength] OF CHAR;
  814.     CharBufPtr    =    ^CharBuffer;
  815.     CharBufHandle    =    ^CharBufPtr;
  816.     
  817.     KeyBufferRecord    =
  818.       RECORD
  819.         bufEmpty:        BOOLEAN;
  820.         bufSize:        INTEGER;
  821.         bufCharCount:    INTEGER;
  822.         bufDelCount:    INTEGER;
  823.         bufSelStart:    INTEGER;
  824.         bufSelEnd:        INTEGER;
  825.         bufWndw:        WindowPtr;
  826.         bufChars:        CharBufHandle;
  827.         bufDesc:        AEDesc;
  828.       END;
  829.     
  830. { END OF TYPES }
  831.  
  832. VAR
  833.     {The "g" prefix is used to emphasize that a variable is global.}
  834.     gMac                : SysEnvRec;    { set up by Initialize }
  835.     gHasWaitNextEvent    : BOOLEAN;        { set up by Initialize }
  836.     gInBackground        : BOOLEAN;        { maintained by Initialize and DoEvent }
  837.     gNumDocuments        : INTEGER;        { maintained by Initialize, MyNewWindow, and DoMenuClose }
  838.     gDocCount:        INTEGER;            { total number of windows open since startup }
  839.     
  840.     {New globals to support printing and style selection }
  841.     gTxStyle             : TextStyle;    { holds style selected, plain default, maintained by DoMenuCommand }
  842.     gFontName             : Str255;        { name of font selected, app font default, maintained by DoMenuCommand }
  843.     gFontID             : INTEGER;        { ID of font selected, app font default, maintained by DoMenuCommand }
  844.     gFontSize             : LONGINT;        { font size selected, 12 pt default, maintained by DoMenuCommand }
  845.     gPrinterRecord        : THPrint;        { print handle, maintained by NewPrintText }
  846.     gPrinterPort        : TPPrPort;        { pointer to Print Manager's GrafPort }
  847.         
  848.     { the following globals are all NEW FOR QUILL }
  849.     
  850.     gTempBool:        BOOLEAN;
  851.     gTempPtr:        Ptr;
  852.     gTempLong:        LongInt;
  853.     gTempInt:        INTEGER;
  854.     gTempType:        DescType;
  855.     
  856.     gActSize:        Size;
  857.     gReturnedType:    DescType;
  858.     
  859.     gQuitNow:        BOOLEAN;
  860.     gProcPtr:        EventHandlerProcPtr;
  861.     
  862.     gNullDesc:        AEDesc;            { initialized in Initialize, disposed of in Terminate }
  863.     gSelfAddrDesc:    AEAddressDesc;    { initialized in Initialize, disposed of in Terminate }
  864.     
  865.     gIndex:            INTEGER;
  866.     
  867.     theStyles:    ARRAY[1..kNumOfStyles] OF MyStylItemRec;
  868.     gAllStyles:    Style;
  869.  
  870.     
  871.     gReturnedKeywd:    AEKeyWord;
  872.     
  873.     gInHandler:        BOOLEAN;
  874.     gShowAllErrs:    BOOLEAN;    { TRUE to show all error dialogs; if FALSE, then error dialogs   }
  875.                                 { will not be displayed from withing AppleEvent handlers.  Other }
  876.                                 { routines, however - including the ones that send AppleEvents - }
  877.                                 { will still put up error dialogs                                }
  878.                                 
  879.     keyBuffer:    KeyBufferRecord;
  880.     
  881.     gErrorDesc:    AEDesc;
  882.     
  883.     gInterMode:        LongInt;
  884.     gTriedDialog:    BOOLEAN;
  885.     
  886. { END OF GLOBAL VARS }
  887.  
  888.  
  889. { START OF FORWARD REFERENCES }
  890.     
  891. { EVENT HANDLERS }
  892. FUNCTION HandleClose(theAppleEvent: AppleEvent; reply: AppleEvent;
  893.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  894. FUNCTION HandleCopy(theAppleEvent: AppleEvent; reply: AppleEvent;
  895.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  896. FUNCTION HandleCreateElement(theAppleEvent: AppleEvent; reply: AppleEvent;
  897.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  898. FUNCTION HandleDeleteElement(theAppleEvent: AppleEvent; reply: AppleEvent;
  899.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  900. FUNCTION HandleDoObjectsExist(theAppleEvent: AppleEvent; reply: AppleEvent;
  901.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  902. FUNCTION HandleCut(theAppleEvent: AppleEvent; reply: AppleEvent;
  903.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  904. FUNCTION HandleGetData(theAppleEvent: AppleEvent; reply: AppleEvent;
  905.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  906. FUNCTION HandleMove(theAppleEvent: AppleEvent; reply: AppleEvent;
  907.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  908. FUNCTION HandleCountElements(theAppleEvent: AppleEvent; reply: AppleEvent;
  909.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  910. FUNCTION HandleOpenApp(theAppleEvent: AppleEvent; reply: AppleEvent;
  911.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  912. FUNCTION HandleOpenDocs(theAppleEvent: AppleEvent; reply: AppleEvent;
  913.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  914. FUNCTION HandlePrint(theAppleEvent: AppleEvent; reply: AppleEvent;
  915.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  916. FUNCTION HandlePaste(theAppleEvent: AppleEvent; reply: AppleEvent;
  917.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  918. FUNCTION HandleQuitApp(theAppleEvent: AppleEvent; reply: AppleEvent;
  919.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  920. FUNCTION HandleSave(theAppleEvent: AppleEvent; reply: AppleEvent;
  921.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  922. FUNCTION HandleSetData(theAppleEvent: AppleEvent; reply: AppleEvent;
  923.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  924.  
  925. { OTHER AE CALLBACKS }
  926. FUNCTION AnythingFromListAccessor(wantClass: DescType; container: AEDesc;
  927.     containerClass: DescType; form: DescType; selectionData: AEDesc;
  928.     VAR value: AEDesc; theRefCon: LongInt): OSErr;                                    FORWARD;
  929. FUNCTION CoerceListOrValToTextStyles(theAEDesc: AEDesc; toType: DescType;
  930.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;                                FORWARD;
  931. FUNCTION CoerceMyDocToMyWndw(theAEDesc: AEDesc; toType: DescType; 
  932.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;                                FORWARD;
  933. FUNCTION CoerceMyTextToStylText(theAEDesc: AEDesc; toType: DescType;
  934.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;                                FORWARD;
  935. FUNCTION CoerceObjToAnything(theAEDesc: AEDesc; toType: DescType;
  936.     handlerRefCon: LongInt; VAR result:  AEDesc): OSErr;                            FORWARD;
  937. FUNCTION CoerceStylTextToIntlText(theAEDesc: AEDesc; toType: DescType;
  938.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;                                FORWARD;
  939. FUNCTION CoerceStylTextToText(theAEDesc: AEDesc; toType: DescType;
  940.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;                                FORWARD;
  941. FUNCTION CoerceTextToIntlText(theAEDesc: AEDesc; toType: DescType;
  942.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;                                FORWARD;
  943. FUNCTION ElemFromAnythingAccessor(wantClass: DescType; container: AEDesc;
  944.     containerClass: DescType; form: DescType; selectionData: AEDesc;
  945.     VAR value: AEDesc; theRefCon: LongInt): OSErr;                                    FORWARD;
  946. FUNCTION MyCompareProc(oper: DescType; obj1: AEDesc; obj2: AEDesc;
  947.     VAR result: BOOLEAN): OSErr;                                                    FORWARD;
  948. FUNCTION MyCountProc(desiredType: DescType; containerClass: DescType;
  949.     container: AEDesc; VAR result: LongInt): OSErr;                                    FORWARD;
  950. FUNCTION MyGetErrorDesc(VAR result: DescPtr): OSErr;                                FORWARD;
  951. FUNCTION PropFromAppAccessor(wantClass: DescType; container: AEDesc ;
  952.     containerClass: DescType; form: DescType; selectionData: AEDesc;
  953.     VAR value: AEDesc; theRefCon: LongInt): OSErr;                                    FORWARD;
  954. FUNCTION PropFromTextAccessor(wantClass: DescType; container: AEDesc ;
  955.     containerClass: DescType; form: DescType; selectionData: AEDesc;
  956.     VAR value: AEDesc; theRefCon: LongInt): OSErr;                                    FORWARD;
  957. FUNCTION PropFromWndwAccessor(wantClass: DescType; container: AEDesc ;
  958.     containerClass: DescType; form: DescType; selectionData: AEDesc;
  959.     VAR value: AEDesc; theRefCon: LongInt): OSErr;                                    FORWARD;
  960. FUNCTION TextElemFromTextAccessor(wantClass: DescType; container: AEDesc ;
  961.     containerClass: DescType; form: DescType; selectionData: AEDesc; VAR value: AEDesc;
  962.     theRefCon: LongInt): OSErr;                                                        FORWARD;
  963. FUNCTION TextElemFromWndwAccessor(wantClass: DescType; container: AEDesc ;
  964.     containerClass: DescType; form: DescType; selectionData: AEDesc; VAR value: AEDesc;
  965.     theRefCon: LongInt): OSErr;                                                        FORWARD;
  966. FUNCTION WndwFromNullAccessor(wantClass: DescType; container: AEDesc ;
  967.     containerClass: DescType; form: DescType; selectionData: AEDesc;
  968.     VAR value: AEDesc; theRefCon: LongInt):  OSErr;                                    FORWARD;
  969.  
  970. { AE UTILITIES }
  971. FUNCTION DisposeSomeDescs(desc1Ptr, desc2Ptr, desc3Ptr, 
  972.     desc4Ptr, desc5Ptr: DescPtr):  OSErr;                                            FORWARD;
  973. FUNCTION GetInteractMode(theAppleEvent: AppleEvent;
  974.     VAR interMode: LongInt): OSErr;                                                    FORWARD;
  975. FUNCTION GetObjSpecFields(theObjSpec: AEDesc; VAR theClass: DescType;
  976.     VAR theCont: AEDesc; VAR theKeyForm: AEKeyword; 
  977.         VAR theKeyData: AEDesc): OSErr;                                                FORWARD;
  978. FUNCTION GotRequiredParams(theAppleEvent: AppleEvent):  OSErr;                        FORWARD;
  979. PROCEDURE InitAEHandlers;                                                            FORWARD;
  980. PROCEDURE InitSomeDescs(desc1Ptr, desc2Ptr, desc3Ptr,
  981.     desc4Ptr, desc5Ptr: DescPtr);                                                    FORWARD;
  982. FUNCTION MakeInsertionLoc(relObj: AEDesc; position: DescType;
  983.     VAR insertionLoc: AEDesc): OSErr;                                                FORWARD;
  984. FUNCTION MakeObjSpec(desiredClass: DescType; theCont: AEDesc;
  985.     keyForm: DescType; keyDataType: DescType; keyDataPtr: Ptr;
  986.     keyDataSize: Size; VAR result: AEDesc):  OSErr;                                    FORWARD;
  987. FUNCTION MakeObjSpecFromIndex(desiredClass: DescType; theCont: AEDesc;
  988.     index: LongInt; VAR result: AEDesc): OSErr;                                        FORWARD;
  989. FUNCTION MakeObjSpecFromName(desiredClass: DescType; theCont: AEDesc;
  990.     name: Str255; VAR result: AEDesc): OSErr;                                        FORWARD;
  991. FUNCTION MakeObjSpecFromRange(desiredClass: DescType; theCont: AEDesc;
  992.     startObj: AEDesc; stopObj: AEDesc; VAR result: AEDesc): OSErr;                    FORWARD;
  993. FUNCTION MakePlainList(VAR plainList: AEdesc): OSErr;                                FORWARD;
  994. FUNCTION MakePropObjSpec(theObj: AEDesc; theProp: DescType;
  995.     VAR result: AEDesc): OSErr;                                                        FORWARD;
  996. FUNCTION MakeSelfAddr(VAR addrDesc: AEAddressDesc):    OSErr;                            FORWARD;
  997. FUNCTION MakeSelTextObj(window: WindowPtr; VAR selTextObj: AEDesc): OSErr;            FORWARD;
  998. PROCEDURE MakeSelTextToken(window: WindowPtr; VAR selTextToken: TextToken);            FORWARD;
  999. FUNCTION MakeSpotObj(wndwIndex: INTEGER; spotIndex: INTEGER;
  1000.     VAR spotObj: AEDesc): OSErr;                                                    FORWARD;
  1001. FUNCTION MakeStylTextDesc(myTextToken: TextToken; VAR theSTDesc: AEDesc): OSErr;    FORWARD;
  1002. FUNCTION MakeTextRangeObj(wndwIndex: INTEGER; startChar: INTEGER;
  1003.     endChar: INTEGER; VAR rangeObj: AEDEsc): OSErr;                                    FORWARD;
  1004. FUNCTION MightWeInteract(interMode: LongInt; VAR mayInteract: BOOLEAN):  OSErr;        FORWARD;
  1005. FUNCTION MyAEChangeDescType(VAR theDesc: AEDesc; newType: DescType): OSErr;            FORWARD;
  1006. FUNCTION MyAECoerceDescPtr(theAEDesc: AEDesc; toType: DescType; dataPtr: Ptr;
  1007.     maximumSize: Size; VAR actualSize: Size):  OSErr;                                FORWARD;
  1008. FUNCTION TextDescToStr(textDesc: AEDesc; VAR destStr: Str255;
  1009.     VAR actSize: Size): OSErr;                                                        FORWARD;
  1010. FUNCTION SmartMakeSelTextObj(window: WindowPtr; VAR selTextObj: AEDesc): OSErr;        FORWARD;
  1011. FUNCTION SmartTokenRep(myToken: TextToken; VAR smartDesc: AEDesc): OSErr;            FORWARD;
  1012. FUNCTION StrToTextDesc(srcStr: Str255; VAR textDesc: AEDesc): OSErr;                FORWARD;
  1013.  
  1014. { MENU ACTIONS }
  1015. PROCEDURE DoMenuClose(window: WindowPtr);                                            FORWARD;
  1016. PROCEDURE DoMenuEdit(window: WindowPtr; editCode: INTEGER);                            FORWARD;    { Cut, Copy, & Paste }
  1017. PROCEDURE DoMenuMathoms(menuItem: INTEGER);                                            FORWARD;
  1018. PROCEDURE DoMenuNew;                                                                FORWARD;
  1019. PROCEDURE DoMenuOpen;                                                                FORWARD;
  1020. PROCEDURE DoMenuPrint;                                                                FORWARD;
  1021. PROCEDURE DoMenuPrintFile;                                                            FORWARD;
  1022. PROCEDURE DoMenuQuit;                                                                FORWARD;
  1023. PROCEDURE DoMenuQuitNow;                                                            FORWARD;
  1024. PROCEDURE DoMenuSave(window: WindowPtr);                                            FORWARD;
  1025. PROCEDURE DoMenuSaveAs(window: WindowPtr);                                            FORWARD;
  1026. PROCEDURE DoMenuStyle(window: WindowPtr; menuItem: INTEGER);                        FORWARD;
  1027.  
  1028. { SENDING APPLEEVENTS }
  1029. PROCEDURE SendAEClose(window: WindowPtr; saveFlag, fileParamFlag: BOOLEAN;
  1030.     fileSpec: FSSpec);                                                                FORWARD;
  1031. PROCEDURE SendAEOpenDoc(myFSSpec: FSSpec);                                            FORWARD;
  1032. PROCEDURE SendAEPrintDoc(docDesc: AEDesc; doInteract: BOOLEAN);                        FORWARD;
  1033. PROCEDURE SendAEQuit(saveOpt: DescType);                                            FORWARD;
  1034. PROCEDURE SendAESave(window: WindowPtr; fileParamFlag: BOOLEAN; 
  1035.     fileSpec: FSSpec);                                                                FORWARD;
  1036. PROCEDURE SendAESetObjProp(theObj: AEDesc; theProp: DescType; theData: AEDesc);        FORWARD;
  1037. PROCEDURE SendAESetWndwPos(index: INTEGER; thePos: Point);                            FORWARD;
  1038. PROCEDURE SendAESetWndwRect(index: INTEGER; theRect: Rect);                            FORWARD;
  1039.  
  1040. { USER PROMPTS FOR FILES }
  1041. FUNCTION AskAboutSave(name: Str255; VAR saveFlag: BOOLEAN): BOOLEAN;                FORWARD;
  1042. FUNCTION AskBeforeClosing(window: WindowPtr; VAR saveFlag: BOOLEAN;
  1043.     VAR docFileGood: BOOLEAN; VAR fileSpec: FSSpec):    BOOLEAN;                    FORWARD;
  1044. FUNCTION AskForFile(name: Str255; VAR fileSpec: FSSpec):  BOOLEAN;                    FORWARD;
  1045. FUNCTION AskUser( question: Str255 ): INTEGER;                                        FORWARD;
  1046.  
  1047. { SOME IMPORTANT ACTIVITIES }
  1048. FUNCTION DecodeOrdinal(ordData: AEDesc; count: LongInt; VAR index: LongInt; 
  1049.     VAR allFlag: BOOLEAN; VAR zeroFlag: BOOLEAN): OSErr;                            FORWARD;
  1050. FUNCTION DeleteThisObj(myObj: AEDesc): OSErr;                                        FORWARD;
  1051. FUNCTION GetDataFromAppProp(appPropDesc: AEDesc;
  1052.     VAR propDataDesc: AEDesc): OSErr;                                                FORWARD;
  1053. FUNCTION GetDataFromToken(myToken: AEDesc; reqTypesList: AEDesc; 
  1054.     VAR dataDesc: AEDesc; VAR notToken: BOOLEAN): OSErr;                            FORWARD;
  1055. FUNCTION GetDataFromTokenList(myList: AEDesc; reqTypesList: AEDesc; 
  1056.     VAR dataList: AEDesc): OSErr;                                                    FORWARD;
  1057. FUNCTION GetSingularData(srcDesc: AEDesc; reqType: DescType;
  1058.     VAR dataDesc: AEDesc): OSErr;                                                    FORWARD;
  1059. FUNCTION GetStylTextData(textDesc: AEDesc; VAR dataDesc: AEDesc): OSErr;            FORWARD;
  1060. FUNCTION GetWildTypes(myToken: AEDesc; VAR bestType: DescType; 
  1061.     VAR defType: DescType): OSErr;                                                    FORWARD;
  1062. FUNCTION MatchToReqList(srcDesc: AEDesc; reqList: AEDesc; bestType: DescType;
  1063.     defType: DescType; VAR dstDesc: AEDesc): OSErr;                                    FORWARD;
  1064. FUNCTION MyNewWindow(VAR window: WindowPtr): OSErr;                                    FORWARD;
  1065. FUNCTION MyOpenWindow(myFSSpec: FSSpec):  OSErr;                                    FORWARD;
  1066. FUNCTION NewPrintText( hTE : TEHandle; useDialog: BOOLEAN ): OSErr;                    FORWARD;
  1067. FUNCTION PrintFile(myFSS: FSSpec): OSErr;                                            FORWARD;
  1068. FUNCTION PrintFileList(theList: AEDesc): OSErr;                                        FORWARD;
  1069. PROCEDURE PostHandler(reply: AppleEvent; errNum: OSErr);                            FORWARD;
  1070. PROCEDURE PreHandler;                                                                FORWARD;
  1071. FUNCTION RealCountProc(desiredType: DescType; container: AEDesc;
  1072.     VAR result: LongInt): OSErr;                                                    FORWARD;
  1073. FUNCTION SetDataForAppProp(appPropDesc: AEDesc; propDataDesc: AEDesc): OSErr;        FORWARD;
  1074. FUNCTION SetDataForToken(myToken: AEDesc; dataDesc: AEDesc): OSErr;                    FORWARD;
  1075. FUNCTION SetDataForTokenList(myList: AEDesc; dataDesc: AEDesc): OSErr;                FORWARD;
  1076. FUNCTION SetStylTextData(textDesc: AEDesc; dataDesc: AEDesc): OSErr;                FORWARD;
  1077. FUNCTION SetUpEdit(theAppleEvent: AppleEvent; VAR window: WindowPtr): OSErr;        FORWARD;
  1078.  
  1079.  
  1080. { TERMINATION ROUTINES }
  1081. FUNCTION CloseAllAskUser(VAR userCancelled: BOOLEAN): OSErr;                        FORWARD;
  1082. PROCEDURE CloseAllNoSave;                                                            FORWARD;
  1083. FUNCTION CloseAllWithSave: OSErr;                                                    FORWARD;
  1084. FUNCTION MyTerminate(saveOpt: DescType; VAR userCancelled: BOOLEAN): OSErr;            FORWARD;
  1085. FUNCTION SmartCloseAll(saveOpt: DescType;  VAR userCancelled: BOOLEAN):  OSErr;        FORWARD;
  1086.  
  1087. { WINDOW INFO & HANDLING }
  1088. FUNCTION BackWindow:  WindowPtr;                                                    FORWARD;
  1089. PROCEDURE CleanWindow(window: WindowPtr);                                            FORWARD;
  1090. FUNCTION CountWindows: INTEGER;                                                        FORWARD;
  1091. PROCEDURE DirtyWindow(window: WindowPtr);                                            FORWARD;
  1092. PROCEDURE DoDragWindow(theWindow: WindowPtr; startPt: Point; boundsRect: Rect);        FORWARD;
  1093. FUNCTION GetDataFromWndwProp(wndwPropDesc: AEDesc;
  1094.     VAR propDataDesc: AEDesc): OSErr;                                                FORWARD;
  1095. FUNCTION GetWindowProp(window: WindowPtr; theProp: DescType; 
  1096.     VAR dataDesc: AEDesc): OSErr;                                                    FORWARD;
  1097. FUNCTION IndexFromWndwPtr(window: WindowPtr): INTEGER;                                FORWARD;
  1098. FUNCTION MakeWindowList(VAR wndwList: AEDesc; myType: DescType): OSErr;                FORWARD;
  1099. PROCEDURE MyBringWndwFront(window: WindowPtr);                                        FORWARD;
  1100. FUNCTION MySendWindow(aWindow: WindowPtr; bWindow: WindowPtr;
  1101.     whereMod: DescType): OSErr;                                                        FORWARD;
  1102. FUNCTION SetWindowProp(window: WindowPtr; theProp: DescType; 
  1103.     propData: AEDesc): OSErr;                                                        FORWARD;
  1104. FUNCTION SetDataForWndwProp(wndwPropDesc: AEDesc; propDataDesc: AEDesc): OSErr;        FORWARD;
  1105. PROCEDURE ShutTheWindow(window: WindowPtr);                                            FORWARD;
  1106. FUNCTION WindowIsDirty(window: WindowPtr): BOOLEAN;                                    FORWARD;
  1107. FUNCTION WndwPtrFromIndex(index: INTEGER): WindowPtr;                                FORWARD;
  1108. FUNCTION WndwPtrFromName(name: Str255): WindowPtr;                                    FORWARD;
  1109.  
  1110. { FILE UTILITIES }
  1111. FUNCTION EqualFSSpecs(aFile, bFile:  FSSpec):  BOOLEAN;                                FORWARD;
  1112. FUNCTION FileToTERec(fileSpec: FSSpec; teHndl: TEHandle): OSErr;                    FORWARD;
  1113. FUNCTION FillHandlesFromFile(VAR listCount: INTEGER;
  1114.     listPtr: HandleListPtr; refNum: INTEGER; VAR xferCount: INTEGER):  OSErr;        FORWARD;
  1115. FUNCTION GetFileAndSaveWndw(window: WindowPtr; useFS: BOOLEAN;
  1116.     VAR fileSpec: FSSpec): OSErr;                                                    FORWARD;
  1117. FUNCTION MyCreateFSS(fileName: Str255; VAR fileSpec: FSSpec):  OSErr;                FORWARD;
  1118. FUNCTION MyMakeFSSForWndw(window: WindowPtr;  VAR theFSS: FSSpec):  OSErr;            FORWARD;
  1119. FUNCTION TERecToFile(teHndl: TEHandle; fileSpec: FSSpec): OSErr;                    FORWARD;
  1120. FUNCTION WriteHandlesToFile(listCount: INTEGER; 
  1121.     listPtr: HandleListPtr; refNum: INTEGER; VAR xferCount: INTEGER):  OSErr;        FORWARD;
  1122.     
  1123. { TEXT INFO & HANDLING }
  1124. FUNCTION CompareTextDescs(text1: AEDesc; text2: AEDesc;
  1125.     VAR result: DescType): OSErr;                                                    FORWARD;
  1126. FUNCTION CountDelChars(textPtr: Ptr; textLength: LongInt;
  1127.     delChar: SignedByte): LongInt;                                                    FORWARD;
  1128. FUNCTION CountTextElems(srcText: TextToken; elemClass: DescType;
  1129.     VAR elemCount: LongInt): OSErr;                                                    FORWARD;
  1130. FUNCTION CountWords(textPtr: Ptr; textLength: LongInt): LongInt;                    FORWARD;
  1131. PROCEDURE DeleteThisText(myText: TextToken);                                        FORWARD;
  1132. FUNCTION DecodeInsertionLoc(insertionLoc: AEDesc; VAR relObjToken: AEDesc; 
  1133.     VAR position: DescType): OSErr;                                                    FORWARD;
  1134. PROCEDURE ExtendTextElem(VAR myText: TextToken);                                    FORWARD;
  1135. PROCEDURE ExtendWord(VAR myText: TextToken);                                        FORWARD;
  1136. FUNCTION GetDataFromTextProp(textPropDesc: AEDesc;
  1137.     VAR propDataDesc: AEDesc): OSErr;                                                FORWARD;
  1138. FUNCTION GetStyleItemFromConst(myConst: DescType; VAR stylItem: StyleItem; 
  1139.     VAR plainFlag: BOOLEAN):  BOOLEAN;                                                FORWARD;
  1140. FUNCTION GetTextElemFromText(srcText: TextToken; elemClass: DescType; 
  1141.     elemIndex: LongInt; VAR elemText: TextToken): OSErr;                            FORWARD;
  1142. FUNCTION GetTextFromDesc(srcDesc: AEDesc; VAR dstDesc: AEDesc): OSErr;                FORWARD;
  1143. PROCEDURE InitTextToken(VAR myText: TextToken);                                        FORWARD;
  1144. PROCEDURE InitTheStyles;                                                            FORWARD;
  1145. FUNCTION IntlTextToText(intlTextDesc: AEDesc; VAR textDesc: AEDesc;
  1146.     VAR scrptCode: ScriptCode; VAR lngCode: LangCode): OSErr;                        FORWARD;
  1147. FUNCTION ListToStyleSet(stylList: AEDesc; VAR styleSet: Style;
  1148.     VAR plainFlag: BOOLEAN; checkStyles: BOOLEAN): OSErr;                            FORWARD;
  1149. FUNCTION MakeElemList(elemClass: DescType; srcText: TextToken;
  1150.     VAR elemList: AEDesc): OSErr;                                                    FORWARD;
  1151. PROCEDURE MakeTextTokenForWndw(window: WindowPtr; VAR wndwText: TextToken);            FORWARD;
  1152. FUNCTION MyDoCut(window: WindowPtr): OSErr;                                            FORWARD;
  1153. FUNCTION MyDoCopy(window: WindowPtr): OSErr;                                        FORWARD;
  1154. FUNCTION MyDoPaste(window: WindowPtr): OSErr;                                        FORWARD;
  1155. FUNCTION MyGetTextElem(textPtr: Ptr; textLength: LongInt; delChar: SignedByte;
  1156.     elemIndex: LongInt; VAR elemOffset: LongInt; VAR elemLength:  LongInt): OSErr;    FORWARD;
  1157. FUNCTION MyGetWord(textPtr: Ptr; textLength: LongInt; wordIndex: LongInt;
  1158.     VAR wordOffset: LongInt; VAR wordLength: LongInt): OSErr;                        FORWARD;
  1159. FUNCTION MyGetUniformStyles(theTE: TEHandle; VAR onStyles: Style;
  1160.     VAR offStyles: Style): OSErr;                                                    FORWARD;
  1161. PROCEDURE ScanToBreak(startPtr: Ptr; endPtr: Ptr; VAR breakPtr: Ptr);                FORWARD;
  1162. PROCEDURE ScanToDelimiter(startPtr: Ptr; endPtr: Ptr; delChar: SignedByte;
  1163.     VAR delPtr: Ptr);                                                                FORWARD;
  1164. PROCEDURE ScanToNonBreak(startPtr: Ptr; endPtr: Ptr; VAR nbPtr: Ptr);                FORWARD;
  1165. FUNCTION SetDataForTextProp(textPropDesc: AEDesc; propDataDesc: AEDesc): OSErr;        FORWARD;
  1166. PROCEDURE SelectTextToken(theTextToken: TextToken);                                    FORWARD;
  1167. PROCEDURE SetFontForSelText(window: WindowPtr; fontName: Str255);                    FORWARD;
  1168. PROCEDURE SetSizeForSelText(window: WindowPtr; newSize: INTEGER);                    FORWARD;
  1169. FUNCTION SetStyleForSelText(window: WindowPtr; onStyles: Style;
  1170.     offStyles: Style): OSErr;                                                        FORWARD;
  1171. FUNCTION SmartMakeStyleData(onStyles: Style; offStyles: Style;
  1172.     VAR styleData: AEDesc): OSErr;                                                    FORWARD;
  1173. FUNCTION StyleDescToStyleSets(styleDesc: AEDesc; VAR onStyles: Style;
  1174.     VAR offStyles: Style; checkStyles: BOOLEAN):  OSErr;                            FORWARD;
  1175. FUNCTION StyleSetsToStyleDesc(onStyles: Style; offStyles: Style;
  1176.     VAR styleDesc: AEDesc; checkStyles: BOOLEAN; usePlain: BOOLEAN):  OSErr;        FORWARD;
  1177. FUNCTION StyleSetToList(styleSet: Style; VAR stylList: AEDesc): OSErr;                FORWARD;
  1178. FUNCTION TextTokenToDesc(srcText: TextToken; VAR dstDesc: AEDesc): OSErr;            FORWARD;
  1179. FUNCTION TextToIntlText(textDesc: AEDesc; scrptCode: ScriptCode;
  1180.     lngCode: LangCode; VAR intlTextDesc: AEDesc): OSErr;                            FORWARD;
  1181.  
  1182.  
  1183. { KEY BUFFERING }
  1184. PROCEDURE CheckKeyBuffer;                                                            FORWARD;
  1185. PROCEDURE ContinueKeyBuffering(key: CHAR; window: WindowPtr);                        FORWARD;
  1186. PROCEDURE DestroyKeyBuffer;                                                            FORWARD;
  1187. FUNCTION GrowKeyBuffer:  BOOLEAN;                                                    FORWARD;
  1188. PROCEDURE InitKeyBuffer;                                                            FORWARD;
  1189. PROCEDURE InitKeyBufVals;                                                            FORWARD;
  1190. PROCEDURE MyAEDoKey(key: CHAR; window: WindowPtr);                                    FORWARD;
  1191. PROCEDURE ResetKeyBuffer;                                                            FORWARD;
  1192. PROCEDURE StartKeyBuffering(key: CHAR; window: WindowPtr);                            FORWARD;
  1193.  
  1194. { TOKEN/LIST ROUTINES }
  1195. FUNCTION CloseToken(theToken: AEDesc; saveOpt: DescType; gotDestFile: BOOLEAN;
  1196.     destFile: FSSpec): OSErr;                                                        FORWARD;
  1197. FUNCTION CloseTokenList(theList: AEDesc; saveOpt: DescType; gotDestFile: BOOLEAN;
  1198.     destFile: FSSpec): OSErr;                                                        FORWARD;
  1199. FUNCTION MoveToken(theToken: AEDesc; relObjToken: AEDesc;
  1200.     position: DescType): OSErr;                                                        FORWARD;
  1201. FUNCTION MoveTokenList(theList: AEDesc; relObjToken: AEDesc;
  1202.     position: DescType): OSErr;                                                        FORWARD;
  1203. FUNCTION PrintToken(theToken: AEDesc): OSErr;                                        FORWARD;
  1204. FUNCTION PrintTokenList(theList: AEDesc): OSErr;                                    FORWARD;
  1205.  
  1206. { MISC UTILITIES }
  1207. FUNCTION BoolToStr(theBool: BOOLEAN): Str15;                                        FORWARD;
  1208. FUNCTION MyNumToStr(theNum: LONGINT): Str255;                                        FORWARD;
  1209. FUNCTION MyRandom(count: LongInt): LongInt;                                            FORWARD;
  1210.  
  1211. { ERROR HANDLING }
  1212. FUNCTION CatchErr(theErr: OSErr; placeNum: INTEGER; VAR holdErr: OSErr):  BOOLEAN;    FORWARD;
  1213. FUNCTION CheckErr(theErr: OSErr; placeNum: INTEGER):  BOOLEAN;                        FORWARD;
  1214. PROCEDURE DoItemErr(itemNum: INTEGER; theErr: OSErr; placeNum: INTEGER);             FORWARD;
  1215. PROCEDURE DoMyAlert(alertStr: Str255);                                                FORWARD;
  1216. PROCEDURE DoMyErr(theErr: OSErr; placeNum: INTEGER);                                FORWARD;
  1217. FUNCTION QuietCatchErr(theErr: OSErr; VAR holdErr: OSErr): BOOLEAN;                    FORWARD;
  1218.  
  1219. { AND . . . . }
  1220. PROCEDURE DoHighLevelEvent(event: EventRecord);                                        FORWARD;
  1221.  
  1222. FUNCTION TypeToStr(thisType: DescType): Str15;                                        FORWARD;
  1223. PROCEDURE ShowObj(theObjSpec: AEDesc);                                                FORWARD;
  1224. PROCEDURE ShowEventAttrs(theAppleEvent: AppleEvent);                                FORWARD;
  1225. FUNCTION HandleWild(theAppleEvent: AppleEvent; reply: AppleEvent;
  1226.     handlerRefCon: LongInt): OSErr;                                                    FORWARD;
  1227. FUNCTION QuietGetSingularData(srcDesc: AEDesc; reqType: DescType;
  1228.     VAR dataDesc: AEDesc): OSErr;                                                    FORWARD;
  1229.     
  1230.     
  1231. { END OF FORWARDS }
  1232.  
  1233.  
  1234. { ROUTINES }
  1235.     
  1236. {$S Initialize}
  1237. FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
  1238.  
  1239. {Check to see if a given trap is implemented. This is only used by the
  1240.  Initialize routine in this program, so we put it in the Initialize segment.
  1241.  The recommended approach to see if a trap is implemented is to see if
  1242.  the address of the trap routine is the same as the address of the
  1243.  Unimplemented trap.}
  1244. {Needs to be called after call to SysEnvirons so that it can check
  1245.  if a ToolTrap is out of range of a pre-MacII ROM.}
  1246.  
  1247. BEGIN
  1248.     IF (tType = ToolTrap) &
  1249.         (gMac.machineType > envMachUnknown) &
  1250.         (gMac.machineType < envMacII) THEN BEGIN        {it's a 512KE, Plus, or SE}
  1251.         tNumber := BAND(tNumber, $03FF);
  1252.         IF tNumber > $01FF THEN                            {which means the tool traps}
  1253.             tNumber := _Unimplemented;                    {only go to $01FF}
  1254.     END;
  1255.     TrapAvailable := NGetTrapAddress(tNumber, tType) <>
  1256.                         GetTrapAddress(_Unimplemented);
  1257. END; {TrapAvailable}
  1258.  
  1259.  
  1260. {$S Main}
  1261. FUNCTION IsDAWindow( window : WindowPtr ) : BOOLEAN;
  1262.  
  1263. {  Check if a window belongs to a desk accessory. }
  1264.  
  1265. BEGIN { IsDAWindow }
  1266.     IF window = NIL THEN
  1267.         IsDAWindow := FALSE
  1268.     ELSE    { DA windows have negative windowKinds }
  1269.         IsDAWindow := WindowPeek( window )^.windowKind < 0;
  1270. END; { IsDAWindow }
  1271.  
  1272.  
  1273.  
  1274. {$S Main}
  1275. FUNCTION IsAppWindow( window : WindowPtr ) : BOOLEAN;
  1276.  
  1277. {  Check if a window belongs to the application. }
  1278.  
  1279. BEGIN { IsAppWindow }
  1280.     IF window = NIL THEN
  1281.         IsAppWindow := FALSE
  1282.     ELSE    { application windows have non-negative windowKinds }
  1283.         IsAppWindow := WindowPeek( window )^.windowKind >= 0;
  1284. END; { IsAppWindow }
  1285.  
  1286.  
  1287.  
  1288. {$S Main}
  1289. PROCEDURE AlertUser( error : INTEGER );
  1290.  
  1291. {  Display an alert that tells the user an error occurred, then exit the program }
  1292.  
  1293. VAR
  1294.     itemHit    : INTEGER;
  1295.     message    : Str255;
  1296.  
  1297. BEGIN { AlertUser }
  1298.     SetCursor( arrow );
  1299.     GetIndString( message, kErrStrings, error );
  1300.     ParamText(message, '', '', '');
  1301.     itemHit := Alert( rUserError, NIL );
  1302. END; { AlertUser }
  1303.  
  1304.  
  1305. {$S Main}
  1306. PROCEDURE GetTERect( window : WindowPtr; VAR teRect : Rect);
  1307.  
  1308. {   return a rectangle that is inset from the portRect by the size of
  1309.     the scrollbars and a little extra margin. }
  1310.  
  1311. BEGIN { GetTERect }
  1312.     teRect := window^.portRect;
  1313.     InsetRect( teRect, kTextMargin, kTextMargin );        { adjust for margin }
  1314.     teRect.bottom := teRect.bottom - kScrollbarAdjust;    { and for the scrollbars }
  1315.     teRect.right := teRect.right - kScrollbarAdjust;
  1316. END; { GetTERect }
  1317.  
  1318.  
  1319.  
  1320. {$S Main}
  1321. PROCEDURE AdjustTE( window : WindowPtr );
  1322.  
  1323. {    Scroll the TERec around to match up to the potentially updated scrollbar
  1324.     values. This is really useful when the window resizes such that the
  1325.     scrollbars become inactive and the TERec had been previously scrolled. }
  1326.  
  1327. VAR
  1328.     value    : INTEGER;
  1329.     
  1330. BEGIN { AdjustTE }
  1331.     WITH DocumentPeek( window )^ DO BEGIN
  1332.         TEScroll( ( docTE^^.viewRect.left - docTE^^.destRect.left ) - GetCtlValue( docHScroll ),
  1333.                 ( docTE^^.viewRect.top - docTE^^.destRect.top ) -
  1334.                 GetCtlValue( docVScroll ) , docTE );
  1335.     END; { with }
  1336. END; { AdjustTE }
  1337.  
  1338.  
  1339.  
  1340. {$S Main}
  1341. PROCEDURE AdjustHV( isVert : BOOLEAN; control : ControlHandle; 
  1342.                     docTE : TEHandle; canRedraw : BOOLEAN );
  1343.                     
  1344. {Calculate the new control maximum value and current value, whether it is the horizontal or
  1345. vertical scrollbar. The vertical max is calculated by comparing the number of lines to the
  1346. vertical size of the viewRect. The horizontal max is calculated by comparing the maximum document
  1347. width to the width of the viewRect. The current values are set by comparing the offset between
  1348. the view and destination rects. If necessary and we canRedraw, have the control be re-drawn by
  1349. calling ShowControl.}
  1350.  
  1351. {TEStyleSample-vertical max originally used line by line calculations-lineheight was a
  1352. constant value so it was easy to figure out what the range should be and pin the value
  1353. within range. Now we need to use max and min values in pixels rather than in nlines}
  1354.  
  1355. VAR
  1356.     value, max             : INTEGER;
  1357.     oldValue, oldMax    : INTEGER;
  1358.     
  1359. BEGIN { AdjustHV }
  1360.     oldValue := GetCtlValue( control );
  1361.     oldMax := GetCtlMax( control );
  1362.     IF isVert THEN BEGIN
  1363.         { new for TEStyleSample }
  1364.         max := ( TEGetHeight( docTE^^.nLines, 0, docTE ) ) - 
  1365.                             ( docTE^^.viewRect.bottom - docTE^^.viewRect.top );
  1366.         
  1367.     END ELSE
  1368.         max := kMaxDocWidth - (docTE^^.viewRect.right - docTE^^.viewRect.left );
  1369.     
  1370.     IF max < 0 THEN
  1371.         max := 0;            { check for negative values }
  1372.     SetCtlMax( control, max );
  1373.     IF isVert THEN
  1374.         value := docTE^^.viewRect.top - docTE^^.destRect.top 
  1375.     ELSE
  1376.         value := docTE^^.viewRect.left - docTE^^.destRect.left;
  1377.     IF value < 0 THEN
  1378.         value := 0
  1379.     ELSE IF value > max THEN
  1380.         value := max;        { pin the value to within range }
  1381.     SetCtlValue( control, value );
  1382.     IF canRedraw & ( ( max <> oldMax ) | ( value <> oldValue ) ) THEN
  1383.         ShowControl( control );            { check to see if the control can be re-drawn }
  1384. END; { AdjustHV }
  1385.  
  1386.  
  1387.  
  1388. {$S Main}
  1389. PROCEDURE AdjustScrollValues( window : WindowPtr; canRedraw : BOOLEAN );
  1390.  
  1391. {    Simply call the common adjust routine for the vertical and horizontal scrollbars. }
  1392.  
  1393. BEGIN { AdjustScrollValues }
  1394.     WITH DocumentPeek( window )^ DO BEGIN
  1395.         AdjustHV( TRUE, docVScroll, docTE, canRedraw );
  1396.         AdjustHV( FALSE, docHScroll, docTE, canRedraw );
  1397.     END; { with }
  1398. END; { AdjustScrollValues }
  1399.  
  1400.  
  1401.  
  1402. {$S Main}
  1403. PROCEDURE AdjustScrollSizes( window : WindowPtr );
  1404.  
  1405. {    Re-calculate the position and size of the viewRect and the scrollbars.
  1406.      kScrollTweek compensates for off-by-one requirements of the scrollbars
  1407.     to have borders coincide with the growbox. }
  1408.  
  1409. VAR
  1410.     teRect    : Rect;
  1411.  
  1412. BEGIN { AdjustScrollSizes }
  1413.     GetTERect( window, teRect ); {start with teRect}
  1414.     WITH DocumentPeek( window )^, window^.portRect DO BEGIN
  1415.         docTE^^.viewRect := teRect;
  1416.         
  1417.         { AdjustViewRect(docTE) was removed--no longer needed }
  1418.         
  1419.         MoveControl( docVScroll, right - kScrollbarAdjust, -1 );
  1420.         SizeControl( docVScroll, kScrollbarWidth, ( bottom - top ) -
  1421.                         ( kScrollbarAdjust - kScrollTweek ) );
  1422.         MoveControl( docHScroll, -1, bottom - kScrollbarAdjust );
  1423.         SizeControl( docHScroll, ( right - left ) - ( kScrollbarAdjust -
  1424.                         kScrollTweek ), kScrollbarWidth );
  1425.     END; { with }
  1426. END; { AdjustScrollSizes }
  1427.  
  1428.  
  1429.  
  1430. {$S Main}
  1431. PROCEDURE AdjustScrollbars( window : WindowPtr; needsResize : BOOLEAN );
  1432.  
  1433. {    Turn off the controls by jamming a zero into their contrlVis fields 
  1434.     (HideControl erases them and we don't want that). If the controls are to 
  1435.     be resized as well, call the procedure to do that, then call the procedure 
  1436.     to adjust the maximum and current values. Finally re-enable the controls
  1437.     by jamming a $FF in their contrlVis fields. }
  1438.  
  1439. VAR
  1440.     oldMax, oldVal    : INTEGER;
  1441.  
  1442. BEGIN { AdjustScrollbars }
  1443.     WITH DocumentPeek( window )^ DO BEGIN
  1444.         docVScroll^^.contrlVis := kControlInvisible; { turn them off }
  1445.         docHScroll^^.contrlVis := kControlInvisible;
  1446.         IF needsResize THEN                            { move and size if needed }
  1447.             AdjustScrollSizes( window );
  1448.         AdjustScrollValues( window, NOT needsResize ); { fool with max and current value }
  1449.         { Now, restore visibility in case we never had to ShowControl during adjustment }
  1450.         docVScroll^^.contrlVis := kControlVisible; { turn them on }
  1451.         docHScroll^^.contrlVis := kControlVisible;
  1452.     END;
  1453. END; { AdjustScrollbars }
  1454.  
  1455.  
  1456.  
  1457. {$S Main}
  1458. {$PUSH} {$Z+}
  1459. PROCEDURE PascalClikLoop;
  1460.  
  1461. {    Gets called from our assembly language routine, AsmClikLoop, which is in
  1462.      turn called by the TEClick toolbox routine. Saves the windows clip region,
  1463.      sets it to the portRect, adjusts the scrollbar values to match the TE scroll
  1464.      amount, then restores the clip region. }
  1465.  
  1466. VAR
  1467.     window : WindowPtr;
  1468.     region : RgnHandle;
  1469.  
  1470. BEGIN { PascalClikLoop }
  1471.     window := FrontWindow;
  1472.     region := NewRgn;
  1473.     GetClip( region ); { save the old clip }
  1474.     ClipRect( window^.portRect ); { set the new clip }
  1475.     AdjustScrollValues( window, TRUE ); { pass TRUE for canRedraw }
  1476.     SetClip( region ); { restore the old clip }
  1477.     DisposeRgn( region );
  1478. END; { PascalClikLoop }
  1479. {$POP}
  1480.  
  1481.  
  1482.  
  1483. {$S Main}
  1484. {$PUSH} {$Z+}
  1485. FUNCTION GetOldClikLoop : ProcPtr;
  1486.  
  1487. {    Gets called from our assembly language routine, AsmClikLoop, which is in
  1488.     turn called by the TEClick toolbox routine. It returns the address of the
  1489.     default clikLoop routine that was put into the TERec by TEAutoView to
  1490.     AsmClikLoop so that it can call it. }
  1491.  
  1492. BEGIN { GetOldClikLoop }
  1493.     GetOldClikLoop := DocumentPeek( FrontWindow )^.docClik;
  1494. END; { GetOldClikLoop }
  1495. {$POP}
  1496.  
  1497.  
  1498.  
  1499. PROCEDURE AsmClikLoop; EXTERNAL;
  1500.  
  1501. {    A reference to our assembly language routine that gets attached to the clikLoop
  1502.     field of our TE record. }
  1503.  
  1504.  
  1505. {$S Main}
  1506. PROCEDURE BigBadError( error : INTEGER );
  1507. BEGIN
  1508.     AlertUser( error );
  1509.     ExitToShell;
  1510. END;
  1511.  
  1512.  
  1513.  
  1514. {$S Initialize}
  1515. PROCEDURE Initialize;
  1516.  
  1517. {    Set up the whole world, including global variables, Toolbox managers,
  1518.      menus, and a single blank document.}
  1519.     
  1520. {If an error is detected, instead of merely doing an ExitToShell,
  1521.  which leaves the user without much to go on, we call AlertUser, which puts
  1522.  up a simple alert that just says an error occurred and then calls ExitToShell.
  1523.  Since there is no other cleanup needed at this point if an error is detected,
  1524.  this form of error- handling is acceptable. If more sophisticated error recovery
  1525.  is needed, an exception mechanism, such as is provided by Signals, can be used.}
  1526. { CHANGES FOR QUILL:
  1527.   (1) moved up gHasWaitNextEvent
  1528.   (2) put in InitAEHandlers
  1529.   (3) commented out the grab-3-events stuff - **CHECK
  1530.   (4) put in gDocCount
  1531.   (5) took out the DoNew (the OpenApp event takes care of it)
  1532.   (6) init gNullDesc and gSelfAddrDesc
  1533. }
  1534.  
  1535. VAR
  1536.     menuBar                : Handle;
  1537.     total, contig        : LongInt;
  1538.     event                : EventRecord;
  1539.     count                : INTEGER;
  1540.     
  1541.     PROCEDURE BigBadError( error : INTEGER );
  1542.     BEGIN
  1543.         AlertUser( error );
  1544.         ExitToShell;
  1545.     END;
  1546.  
  1547. BEGIN { Initialize }
  1548.     gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);    { **CHECK on this }
  1549.     gInBackground := FALSE;
  1550.     
  1551.     gErrorDesc := gNullDesc;
  1552.  
  1553.     InitGraf(@thePort);
  1554.     InitFonts;
  1555.     InitWindows;
  1556.     InitMenus;
  1557.     TEInit;
  1558.     InitDialogs(NIL);
  1559.     InitCursor;
  1560.     InitAEHandlers;
  1561.     InitTheStyles;
  1562.     
  1563.     gInHandler := FALSE;
  1564.     gShowAllErrs := FALSE;
  1565.     
  1566.     
  1567.     FOR count := 1 TO 3 DO
  1568.         gTempBool := EventAvail(everyEvent, event);    { **CHECK on this, too }
  1569.     gTempLong := SysEnvirons(kSysEnvironsVersion, gMac);
  1570.     IF gMac.machineType < 0 THEN BigBadError(eWrongMachine);
  1571.  
  1572.     
  1573.     IF ORD( GetApplLimit ) - ORD( ApplicZone ) < kMinHeap THEN
  1574.         BigBadError( eSmallSize );
  1575.     PurgeSpace( total, contig );
  1576.     IF total < kMinSpace THEN
  1577.         IF UnloadScrap <> noErr THEN
  1578.             BigBadError( eNoMemory )
  1579.         ELSE BEGIN
  1580.             PurgeSpace( total, contig );
  1581.             IF total < kMinSpace THEN
  1582.                 BigBadError( eNoMemory );
  1583.         END; { if }
  1584.  
  1585.     menuBar := GetNewMBar( rMenuBar ); { read menus into menu bar }
  1586.     IF menuBar = NIL THEN
  1587.         BigBadError( eNoMemory );
  1588.     SetMenuBar( menuBar ); { install menus }
  1589.     DisposHandle( menuBar );
  1590.     AddResMenu( GetMHandle( mApple ), 'DRVR' );    { add DA names to Apple menu }
  1591.     AddResMenu( GetMHandle( mFont ),'FONT' ); { add Font names to Font Menu }
  1592.     DrawMenuBar;
  1593.     gNumDocuments := 0;
  1594.     gDocCount := 0;
  1595.     { do other initialization here }
  1596.     { set up printer stuff-this will allow the default pageSetup parameters to be used, so if
  1597.       the used decides to print with out using pageSetup everything will be okay }
  1598.       
  1599.     { create a "null descriptor" to serve as a default container }
  1600.     gNullDesc.descriptorType := typeNull;
  1601.     gNullDesc.dataHandle := NIL;
  1602.     
  1603.     { create a address descriptor for sending things to myself }
  1604.     IF CheckErr(   MakeSelfAddr(gSelfAddrDesc) , 3714 ) THEN BigBadError(eNoSelfAddr);
  1605.       
  1606.     gPrinterRecord := THPrint( NewHandle( SizeOF( TPrint ) ) ); {allocate a print record}
  1607.     IF gPrinterRecord <> NIL THEN BEGIN {if we're successful then setup the default settings}
  1608.         PrOpen; {open the record }
  1609.         PrintDefault( gPrinterRecord ); { load in default settings }
  1610.         PrClose; { close it up }
  1611.     END; { if }
  1612.     
  1613.   InitKeyBuffer;
  1614.  
  1615. END; {Initialize}
  1616.  
  1617. {$S Main}
  1618. PROCEDURE AdjustMenus;
  1619. { CHANGES FOR QUILL:  new menu items, multiple windows } 
  1620.  
  1621. VAR
  1622.     window            : WindowPtr;
  1623.     menu            : MenuHandle;
  1624.     offset            : LONGINT;
  1625.     undo            : BOOLEAN;    { flag to enable/disable undo command }
  1626.     cutCopyClear    : BOOLEAN;    { flag to enable/disable editing commands }
  1627.     paste            : BOOLEAN;    
  1628.     selectAll        : BOOLEAN;    
  1629.     
  1630.     doPrint            : BOOLEAN;    { flag to enable/disable printing item }
  1631.     
  1632.     te                : TEHandle;    { local te handle }
  1633.     mode            : INTEGER;    { current style }
  1634.     
  1635.  
  1636. BEGIN
  1637.     window := FrontWindow;
  1638.  
  1639.     menu := GetMHandle( mFile );
  1640.     EnableItem(menu,iQuit);    { always enabled }
  1641.     EnableItem(menu,iQuitNow);    { always enabled }
  1642.     EnableItem(menu,iPrintFile);    { always enabled }
  1643.     
  1644.     IF gNumDocuments < kMaxOpenDocuments THEN
  1645.       BEGIN
  1646.         EnableItem( menu, iNew );    { New, Open enabled when we can open more documents }
  1647.         EnableItem(menu,iOpen);
  1648.       END
  1649.     ELSE
  1650.       BEGIN
  1651.         DisableItem( menu, iNew );
  1652.         DisableItem(menu,iOpen);
  1653.       END;
  1654.     
  1655.     IF window <> NIL THEN { Close, Save, SaveAs enabled when there is an active window }  { well, Save is a special case }
  1656.       BEGIN
  1657.         EnableItem( menu, iClose );
  1658.         IF WindowIsDirty(window) THEN EnableItem( menu , iSave ) ELSE DisableItem(menu,iSave);
  1659.         EnableItem( menu, iSaveAs);
  1660.       END
  1661.     ELSE
  1662.       BEGIN
  1663.         DisableItem( menu, iClose );
  1664.         DisableItem( menu , iSave );
  1665.         DisableItem( menu, iSaveAs );
  1666.       END;
  1667.  
  1668.     menu := GetMHandle( mEdit );
  1669.     undo := FALSE;
  1670.     cutCopyClear := FALSE;
  1671.     paste := FALSE;
  1672.     selectAll := FALSE;
  1673.     doPrint := FALSE;
  1674.     
  1675.     IF IsDAWindow( window ) THEN BEGIN
  1676.         undo := TRUE; { all editing is enabled for DA windows }
  1677.         cutCopyClear := TRUE;
  1678.         paste := TRUE;
  1679.         selectAll := TRUE;
  1680.     END ELSE IF IsAppWindow( window ) THEN BEGIN
  1681.         WITH DocumentPeek( window )^.docTE^^ DO
  1682.             IF selStart < selEnd THEN BEGIN
  1683.                 cutCopyClear := TRUE;
  1684.             END; { if }
  1685.                 { Cut, Copy, and Clear is enabled for app. windows with selections }
  1686.         IF GetScrap( NIL, 'TEXT', offset ) > 0 THEN
  1687.             paste := TRUE; { Paste is enabled for app. windows }
  1688.         
  1689.         selectAll := TRUE;
  1690.         doPrint := TRUE;
  1691.             
  1692.         mode := doFace;
  1693.         menu := GetMHandle( mStyle );
  1694.         IF TEContinuousStyle( mode, gTxStyle, DocumentPeek( window )^.docTE ) THEN BEGIN
  1695.             CheckItem( menu, iPlain, gTxStyle.tsface = [] );
  1696.             CheckItem( menu, iBold, bold in gTxStyle.tsFace );
  1697.             CheckItem( menu, iItalic, italic in gTxStyle.tsFace );
  1698.             CheckItem( menu, iUnderline, underline in gTxStyle.tsFace );
  1699.             CheckItem( menu, iOutline, outline in gTxStyle.tsFace );
  1700.             CheckItem( menu, iShadow, shadow in gTxStyle.tsFace );
  1701.         END ELSE BEGIN
  1702.             CheckItem( menu, iPlain, FALSE );
  1703.             CheckItem( menu, iBold, FALSE );
  1704.             CheckItem( menu, iItalic, FALSE );
  1705.             CheckItem( menu, iUnderline, FALSE );
  1706.             CheckItem( menu, iOutline, FALSE );
  1707.             CheckItem( menu, iShadow, FALSE );
  1708.         END; { if }
  1709.  
  1710.     END; { if }
  1711.     menu := GetMHandle( mEdit );
  1712.     
  1713.     IF undo THEN
  1714.         EnableItem( menu, iUndo )
  1715.     ELSE
  1716.         DisableItem( menu, iUndo );
  1717.     
  1718.     IF cutCopyClear THEN BEGIN
  1719.         EnableItem( menu, iCut );
  1720.         EnableItem( menu, iCopy );
  1721.         EnableItem( menu, iClear );
  1722.     END ELSE BEGIN
  1723.         DisableItem( menu, iCut );
  1724.         DisableItem( menu, iCopy );
  1725.         DisableItem( menu, iClear );
  1726.     END; { if }
  1727.     
  1728.     
  1729.     IF paste THEN
  1730.         EnableItem( menu, iPaste )
  1731.     ELSE
  1732.         DisableItem( menu, iPaste );
  1733.         
  1734.     IF selectAll THEN 
  1735.         EnableItem( menu, iSelectAll )
  1736.     ELSE
  1737.         DisableItem( menu, iSelectAll );
  1738.  
  1739.         
  1740.     menu := GetMHandle( mFile );
  1741.     IF doPrint THEN BEGIN
  1742.         EnableItem( menu, iPageSetup );
  1743.         EnableItem( menu, iPrint );
  1744.     END ELSE BEGIN
  1745.         DisableItem( menu, iPageSetup );
  1746.         DisableItem( menu, iPrint );
  1747.     END; { if }
  1748.     
  1749.     menu := GetMHandle(mMathoms);
  1750.     EnableItem(menu,iShowAllErrs);
  1751.     CheckItem(menu,iShowAllErrs,gShowAllErrs);    
  1752.                 
  1753. END; { AdjustMenus }
  1754.  
  1755. {$S Main}
  1756. PROCEDURE DoMenuCommand( menuResult : LONGINT );
  1757.  
  1758. {    This is called when an item is chosen from the menu bar (after calling
  1759.     MenuSelect or MenuKey). It does the right thing for each command. }
  1760. { CHANGES FOR QUILL:  many cases now call new routines that make
  1761.   use of AppleEvents.  Also added new cases. } 
  1762. VAR
  1763.     menuID, menuItem        : INTEGER;
  1764.     itemHit, daRefNum        : INTEGER;
  1765.     daName                    : Str255;
  1766.     
  1767.     tempStr                    : Str255;
  1768.     menu                    : MenuHandle;
  1769.     
  1770.     ignoreResult, saveErr    : OSErr;
  1771.     handledByDA                : BOOLEAN;
  1772.     te                        : TEHandle;
  1773.     window                    : WindowPtr;
  1774.     aHandle                    : Handle;
  1775.     oldSize, newSize        : LONGINT;
  1776.     total, contig            : LONGINT;
  1777.  
  1778.     
  1779. BEGIN
  1780.     window := FrontWindow;
  1781.     menuID := HiWrd( menuResult ); { use built-ins (for efficiency)... }
  1782.     menuItem := LoWrd( menuResult ); { to get menu item number and menu number }
  1783.     te := DocumentPeek( window )^.docTE;
  1784.                 
  1785.     CASE menuID OF
  1786.     
  1787.         mApple:
  1788.             CASE menuItem OF
  1789.                 iAbout:                {bring up alert for About}
  1790.                 BEGIN
  1791.                    { Debugger;}
  1792.                  itemHit := Alert(rAboutAlert, NIL);
  1793.  
  1794.                 END;
  1795.                     
  1796.                 OTHERWISE BEGIN        { all non-About items in this menu are DAs }
  1797.                     GetItem( GetMHandle( mApple ), menuItem, daName );
  1798.                     daRefNum := OpenDeskAcc( daName );
  1799.                 END; { otherwise }
  1800.             END; { case }
  1801.             
  1802.         mFile:
  1803.             CASE menuItem OF
  1804.                 iNew:        DoMenuNew;
  1805.                 iOpen:        DoMenuOpen;
  1806.                 iClose:        DoMenuClose(window);
  1807.                 iSave:        DoMenuSave(window);
  1808.                 iSaveAs:    DoMenuSaveAs(window);
  1809.                 
  1810.                 iPageSetup:
  1811.                   BEGIN
  1812.                     PrOpen;
  1813.                     IF PrError = noErr THEN gTempBool := PrStlDialog( gPrinterRecord );
  1814.                     PrClose;
  1815.                   END; { iPageSetup }
  1816.                   
  1817.                 iPrint:        DoMenuPrint;
  1818.                 iPrintFile:    DoMenuPrintFile;
  1819.                 iQuit:        DoMenuQuit;
  1820.                 iQuitNow:    DoMenuQuitNow;
  1821.             END; { case }
  1822.             
  1823.         mEdit: BEGIN                { call SystemEdit for DA editing & MultiFinder }
  1824.             IF NOT SystemEdit( menuItem -1 ) THEN BEGIN
  1825.                 CASE menuItem OF
  1826.                     
  1827.                     iCut, iCopy, iPaste:  DoMenuEdit(window,menuItem);
  1828.                     
  1829.                     iClear:
  1830.                       BEGIN
  1831.                         TEDelete( te );
  1832.                         DirtyWindow(window);
  1833.                       END;
  1834.                         
  1835.                     iSelectAll:
  1836.                         TESetSelect( 0, te^^.teLength, te );
  1837.                         
  1838.                 END; { case }
  1839.                 if menuItem <> iCopy then
  1840.                     AdjustScrollBars( window, FALSE );
  1841.             END; { if }
  1842.         END; { mEdit }
  1843.         
  1844.         mFont :
  1845.             BEGIN { mFont }
  1846.                 GetItem( GetMHandle( mFont ), menuItem, gFontName );
  1847.                 SetFontForSelText(window,gFontName);
  1848.             END; { mFont }
  1849.             
  1850.         mFontSize :
  1851.             BEGIN { mFontSize }
  1852.                 CASE menuItem OF
  1853.                     iNine        : gFontSize := 9;
  1854.                     iTen        : gFontSize := 10;
  1855.                     iTwelve        : gFontSize := 12;
  1856.                     iFourteen    : gFontSize := 14;
  1857.                     iEighteen    : gFontSize := 18;
  1858.                     iTwoFour    : gFontSize := 24;
  1859.                 END; { case }
  1860.  
  1861.                 SetSizeForSelText(window,gFontSize);
  1862.             END; { mFontSize }
  1863.             
  1864.         mStyle :  DoMenuStyle(window,menuItem);
  1865.         
  1866.         mMathoms:    DoMenuMathoms(menuItem);    
  1867.                         
  1868.     END; { case }
  1869.     HiliteMenu( 0 ); { unhighlight what MenuSelect (or MenuKey) hilited }
  1870. END; { DoMenuCommand }
  1871.  
  1872.  
  1873.  
  1874. {$S Main}
  1875. PROCEDURE DrawWindow( window : WindowPtr );
  1876.  
  1877. {    Draw the contents of an application window. }
  1878.  
  1879. BEGIN { DrawWindow }
  1880.     SetPort( window );
  1881.     WITH window^ DO BEGIN
  1882.         EraseRect( portRect ); { as per TextEdit chapter of Inside Macintosh }
  1883.         DrawControls( window ); { this ordering makes for a better appearance }
  1884.         DrawGrowIcon( window );
  1885.         TEUpdate( portRect, DocumentPeek( window )^.docTE );
  1886.     END; { with }
  1887. END; { DrawWindow }
  1888.  
  1889.  
  1890.  
  1891. {$S Main}
  1892. FUNCTION GetSleep : LONGINT;
  1893.  
  1894. {    Calculate a sleep value for WaitNextEvent. This takes into account the things
  1895.      that DoIdle does with idle time. }
  1896.  
  1897. VAR
  1898.     sleep    : LONGINT;
  1899.     window    : WindowPtr;
  1900.  
  1901. BEGIN { GetSleep }
  1902.     sleep := MAXLONGINT; { default value for sleep }
  1903.     IF NOT gInBackground THEN BEGIN { if we are in front... }
  1904.         window := FrontWindow; { and the front window is ours... }
  1905.         IF IsAppWindow( window ) THEN BEGIN
  1906.             WITH DocumentPeek( window )^.docTE^^ DO
  1907.                 IF selStart = selEnd THEN { and the selection is an insertion point... }
  1908.                     sleep := GetCaretTime; { we need to blink the insertion point }
  1909.         END; { if }
  1910.     END; { if }
  1911.     GetSleep := sleep;
  1912. END; { GetSleep }
  1913.  
  1914.  
  1915.  
  1916. {$S Main}
  1917. PROCEDURE CommonAction( control : ControlHandle; VAR amount : INTEGER );
  1918.  
  1919. {    Common algorithm for setting the new value of a control. It returns the actual amount
  1920.     the value of the control changed. Note the pinning is done for the sake of returning
  1921.     the amount the control value changed. }
  1922.  
  1923. VAR
  1924.     value, max    : INTEGER;
  1925.     window        : WindowPtr;
  1926.  
  1927. BEGIN { CommonAction }
  1928.     value := GetCtlValue( control ); { get current value }
  1929.     max := GetCtlMax( control ); { and max value }
  1930.     amount := value - amount;
  1931.     IF amount < 0 THEN
  1932.         amount := 0
  1933.     ELSE IF amount > max THEN
  1934.         amount := max;
  1935.     SetCtlValue( control, amount );
  1936.     amount := value - amount; { calculate true change }
  1937. END; { CommonAction }
  1938.  
  1939.  
  1940.  
  1941. {$S Main}
  1942. PROCEDURE VActionProc( control : ControlHandle; part : INTEGER );
  1943.  
  1944. {    Determines how much to change the value of the vertical scrollbar by and how
  1945.     much to scroll the TE record. }
  1946.  
  1947. VAR
  1948.     amount    : INTEGER;
  1949.     window    : WindowPtr;
  1950.  
  1951. BEGIN { VActionProc }
  1952.     IF part <> 0 THEN BEGIN
  1953.         window := control^^.contrlOwner;
  1954.         WITH DocumentPeek( window )^, DocumentPeek( window )^.docTE^^ DO BEGIN
  1955.             CASE part OF
  1956.                 inUpButton, inDownButton :
  1957.                     amount := 24;
  1958.                 inPageUp, inPageDown :
  1959.                     amount := viewRect.bottom - viewRect.top; { one page }
  1960.             END; { case }
  1961.             IF ( part = inDownButton ) | ( part = inPageDown ) THEN
  1962.                 amount := -amount; { reverse direction }
  1963.             CommonAction( control, amount );
  1964.             IF amount <> 0 THEN
  1965.                 TEScroll( 0, amount, docTE );
  1966.         END; { with }
  1967.     END; { if }
  1968. END; { VActionProc }
  1969.  
  1970.  
  1971.  
  1972. {$S Main}
  1973. PROCEDURE HActionProc( control : ControlHandle; part : INTEGER );
  1974.  
  1975. {    Determines how much to change the value of the horizontal scrollbar by and how
  1976.     much to scroll the TE record. }
  1977.  
  1978. VAR
  1979.     amount    : INTEGER;
  1980.     window    : WindowPtr;
  1981.  
  1982. BEGIN { HActionProc }
  1983.     IF part <> 0 THEN BEGIN
  1984.         window := control^^.contrlOwner;
  1985.         WITH DocumentPeek( window )^, DocumentPeek( window )^.docTE^^ DO BEGIN
  1986.             CASE part OF
  1987.                 inUpButton, inDownButton :
  1988.                     amount := kButtonScroll; { a few pixels }
  1989.                 inPageUp, inPageDown :
  1990.                     amount := viewRect.right - viewRect.left; { a page }
  1991.             END; { case }
  1992.             IF ( part = inDownButton ) | ( part = inPageDown ) THEN
  1993.                 amount := -amount; { reverse direction }
  1994.             CommonAction( control, amount );
  1995.             IF amount <> 0 THEN
  1996.                 TEScroll( amount, 0, docTE );
  1997.         END; { with }
  1998.     END; { if }
  1999. END; { HActionProc }
  2000.  
  2001.  
  2002.  
  2003. {$S Main}
  2004. PROCEDURE DoIdle;
  2005.  
  2006. {    This is called whenever we get an null event or a mouse-moved event.
  2007.      It takes care of necessary periodic actions. For this program, it calls TEIdle. }
  2008.  
  2009. VAR
  2010.     window    : WindowPtr;
  2011.  
  2012. BEGIN { DoIdle }
  2013.     window := FrontWindow;
  2014.     IF IsAppWindow( window ) THEN
  2015.         TEIdle( DocumentPeek( window )^.docTE );
  2016. END; { DoIdle }
  2017.  
  2018.  
  2019.  
  2020. {$S Main}
  2021. PROCEDURE DoKeyDown( event : EventRecord );
  2022.  
  2023. {    This is called for any keyDown or autoKey events, except when the
  2024.     Command key is held down. It looks at the frontmost window to decide what
  2025.      to do with the key typed. }
  2026.  
  2027. VAR
  2028.     window    : WindowPtr;
  2029.     key        : CHAR;
  2030.     te        : TEHandle;
  2031.  
  2032. BEGIN
  2033.     window := FrontWindow;
  2034.     IF IsAppWindow( window ) THEN BEGIN
  2035.         te := DocumentPeek( window)^.docTE;
  2036.         key := CHR( BAnd( event.message, charCodeMask ) );
  2037.         IF ( key = CHR(kDelChar ) ) |     { don't count deletes }
  2038.             ( te^^.teLength - ( te^^.selEnd - te^^.selStart )
  2039.                             + 1 < kMaxTELength ) THEN BEGIN    { but check haven't gone past }
  2040.                             
  2041.             { we will treat arrow keys (which change the selection) like non-key events - }
  2042.             { that is, check the key buffer, and DON'T buffer the arrow key (we could do  }
  2043.             { more complicated stuff, but is it worth it?)                                }
  2044.             
  2045.             IF (key = CHR(kRightArrow)) | (key = CHR(kLeftArrow)) | (key = CHR(kUpArrow)) | (key = CHR(kDownArrow)) 
  2046.             THEN CheckKeyBuffer
  2047.             ELSE MyAEDoKey(key,window);    { must do this BEFORE TEKey or we won't record the selection range right }
  2048.                             
  2049.             TEKey( key, te );
  2050.             DirtyWindow(window);
  2051.             AdjustScrollbars( window, FALSE );
  2052.         END ELSE
  2053.             { **CHECK - should we even try to dump the key buffer here? }
  2054.             AlertUser( eExceedChar );
  2055.     END; { if }
  2056. END; { DoKeyDown }
  2057.  
  2058.  
  2059.  
  2060. {$S Main}
  2061. PROCEDURE DoContentClick( window : WindowPtr; event : EventRecord );
  2062.  
  2063. {    Called when a mouseDown occurs in the content of a window. }
  2064.  
  2065. VAR
  2066.     mouse        : Point;
  2067.     control        : ControlHandle;
  2068.     part, value    : INTEGER;
  2069.     shiftDown    : BOOLEAN;
  2070.     teRect        : Rect;
  2071.     
  2072. BEGIN { DoContentClick }
  2073.     IF IsAppWindow( window ) THEN BEGIN
  2074.         SetPort( window );
  2075.         mouse := event.where; { get the click position }
  2076.         GlobalToLocal( mouse ); { convert to local coordinates }
  2077.         
  2078.         GetTERect( window, teRect );
  2079.         IF PtInRect( mouse, teRect ) THEN BEGIN
  2080.             shiftDown := BAnd( event.modifiers, shiftKey ) <> 0; { extend if Shift is down }
  2081.             TEClick( mouse, shiftDown, DocumentPeek( window )^.docTE );
  2082.         END ELSE BEGIN
  2083.             part := FindControl( mouse, window, control );
  2084.             WITH DocumentPeek( window )^ DO
  2085.                 CASE part OF
  2086.                     0:;     { do nothing for viewRect case }
  2087.                     inThumb: BEGIN
  2088.                         value := GetCtlValue( control );
  2089.                         part := TrackControl( control, mouse, NIL );
  2090.                         IF part <> 0 THEN BEGIN
  2091.                             value := value - GetCtlValue( control );
  2092.                             IF value <> 0 THEN
  2093.                                 IF control = docVScroll THEN
  2094.                                     TEScroll( 0, value, docTE )
  2095.                                 ELSE
  2096.                                     TEScroll( value, 0, docTE );
  2097.                         END; { if }
  2098.                     END; { inThumb }
  2099.                     OTHERWISE    { must be page or button }
  2100.                         IF control = docVScroll THEN
  2101.                             value := TrackControl( control, mouse, @VActionProc )
  2102.                         ELSE
  2103.                             value := TrackControl( control, mouse, @HActionProc );
  2104.                 END; { case }
  2105.         END; { if }
  2106.     END; { if }
  2107. END; { DoContentClick }
  2108.  
  2109.  
  2110.  
  2111. {$S Main}
  2112. PROCEDURE ResizeWindow( window : WindowPtr );
  2113.  
  2114. {    Called when the window has been resized to fix up the controls and content }
  2115.  
  2116. BEGIN { ResizeWindow }
  2117.     WITH window^ DO BEGIN
  2118.         AdjustScrollbars( window, TRUE );
  2119.         AdjustTE( window );
  2120.         InvalRect( portRect );
  2121.     END;
  2122. END; { ResizeWindow }
  2123.  
  2124.  
  2125.  
  2126. {$S Main}
  2127. PROCEDURE GetLocalUpdateRgn( window : WindowPtr; localRgn : RgnHandle );
  2128.  
  2129. {    Returns the update region in local coordinates }
  2130.  
  2131. BEGIN { GetLocalUpdateRgn }
  2132.     CopyRgn( WindowPeek( window )^.updateRgn, localRgn ); { save old update region }
  2133.     WITH window^.portBits.bounds DO
  2134.         OffsetRgn( localRgn, left, top ); { convert to local coords }
  2135. END; { GetLocalUpdateRgn }
  2136.  
  2137.  
  2138.  
  2139. {$S Main}
  2140. PROCEDURE DoGrowWindow( window : WindowPtr; event : EventRecord );
  2141.  
  2142. {    Called when a mouseDown occurs in the grow box of an active window. In
  2143.      order to eliminate any 'flicker', we want to invalidate only what is
  2144.      necessary. Since ResizeWindow invalidates the whole portRect, we save
  2145.      the old TE viewRect, intersect it with the new TE viewRect, and
  2146.      remove the result from the update region. However, we must make sure
  2147.      that any old update region that might have been around gets put back. }
  2148. { CHANGES FOR QUILL:  added an AppleEvent "set rectangle" call
  2149.   for recording purposes (we let the OS actually grow the window for us,
  2150.   then send an AppleEvent to set the rect of the window to its new value - 
  2151.   a null operation, in effect, but it will record the rect change for us) }
  2152.  
  2153. VAR growResult:        LONGINT;
  2154.     tempRect:        Rect;
  2155.     tempRgn:        RgnHandle;
  2156.     ignoreResult:    BOOLEAN;
  2157.     index:            INTEGER;
  2158.  
  2159. BEGIN { DoGrowWindow }
  2160.   WITH screenBits.bounds DO
  2161.       SetRect( tempRect, kMinDocDim, kMinDocDim, right, bottom ); { set up limiting values }
  2162.   growResult := GrowWindow( window, event.where, tempRect );
  2163.   IF growResult <> 0 THEN  { see if changed size }
  2164.       WITH DocumentPeek( window )^, window^ DO BEGIN
  2165.         tempRect := docTE^^.viewRect; { save old text box }
  2166.         tempRgn := NewRgn;
  2167.         GetLocalUpdateRgn( window, tempRgn ); { get localized update region }
  2168.         SizeWindow( window, LoWrd( growResult ), HiWrd( growResult ), TRUE );
  2169.         ResizeWindow( window );
  2170.         ignoreResult := SectRect( tempRect, docTE^^.viewRect, tempRect ); { find what stayed same }
  2171.         ValidRect( tempRect ); { take it out of update }
  2172.         InvalRgn( tempRgn ); { put back any prior update }
  2173.         DisposeRgn( tempRgn );
  2174.       END; { with }
  2175.   { now, for recording purposes, send an AppleEvent to myself
  2176.     (re)setting the window to its current rectangle }
  2177.   tempRect := WindowPeek(window)^.strucRgn^^.rgnBBox;    { we use the structure rect for that }
  2178.   index := IndexFromWndwPtr(window);
  2179.   SendAESetWndwRect(index,tempRect);
  2180. END; { DoGrowWindow }
  2181.  
  2182.  
  2183.  
  2184. {$S Main}
  2185. PROCEDURE DoZoomWindow( window : WindowPtr; part : INTEGER );
  2186.  
  2187. {    Called when a mouseClick occurs in the zoom box of an active window.
  2188.     Everything has to get re-drawn here, so we don't mind that
  2189.     ResizeWindow invalidates the whole portRect. }
  2190.  
  2191. BEGIN { DoZoomWindow }
  2192.     WITH window^ DO BEGIN
  2193.         EraseRect( portRect );
  2194.         ZoomWindow( window, part, ( window = FrontWindow ) );
  2195.         ResizeWindow( window );
  2196.     END; { with }
  2197. END; { DoZoomWindow }
  2198.  
  2199.  
  2200.  
  2201. {$S Main}
  2202. PROCEDURE DoUpdate( window : WindowPtr );
  2203.  
  2204. {    This is called when an update event is received for a window.
  2205.      It calls DrawWindow to draw the contents of an application window,
  2206.      but only if the visRgn is non-empty; for efficiency reasons,
  2207.      not because it is required. }
  2208.  
  2209. BEGIN { DoUpdate }
  2210.     IF IsAppWindow( window ) THEN BEGIN
  2211.         BeginUpdate( window ); { this sets up the visRgn }
  2212.         IF NOT EmptyRgn( window^.visRgn ) THEN    { draw if updating needs to be done }
  2213.             DrawWindow( window );
  2214.         EndUpdate( window );
  2215.     END; { if }
  2216. END; { DoUpdate }
  2217.  
  2218.  
  2219.  
  2220. {$S Main}
  2221. PROCEDURE DoActivate( window : WindowPtr; becomingActive : BOOLEAN );
  2222.  
  2223. {    This is called when a window is activated or deactivated. }
  2224.  
  2225. VAR
  2226.     tempRgn, clipRgn    : RgnHandle;
  2227.     growRect            : Rect;
  2228.  
  2229. BEGIN { DoActivate }
  2230.     IF IsAppWindow( window ) THEN
  2231.         WITH DocumentPeek( window )^ DO
  2232.             IF becomingActive THEN BEGIN
  2233.                 { since we don’t want TEActivate to draw a selection in an area where
  2234.                   we’re going to erase and redraw, we’ll clip out the update region
  2235.                   before calling it. }
  2236.                 tempRgn := NewRgn;
  2237.                 clipRgn := NewRgn;
  2238.                 GetLocalUpdateRgn( window, tempRgn ); { get localized update region }
  2239.                 GetClip( clipRgn );
  2240.                 DiffRgn( clipRgn, tempRgn, tempRgn ); { subtract updateRgn from clipRgn }
  2241.                 SetClip( tempRgn );
  2242.                 TEActivate( docTE ); { let TE do its thing }
  2243.                 SetClip( clipRgn ); { restore the full-blown clipRgn }
  2244.                 DisposeRgn( tempRgn );
  2245.                 DisposeRgn( clipRgn );
  2246.  
  2247.                 {the controls need to be redrawn on activation:}
  2248.                 docVScroll^^.contrlVis := kControlVisible;
  2249.                 docHScroll^^.contrlVis := kControlVisible;
  2250.                 InvalRect( docVScroll^^.contrlRect );
  2251.                 InvalRect( docHScroll^^.contrlRect );
  2252.                 { the growbox needs to be redrawn on activation: }
  2253.                 growRect := window^.portRect;
  2254.                 WITH growRect DO BEGIN
  2255.                     top := bottom - kScrollbarAdjust; { adjust for the scrollbars }
  2256.                     left := right - kScrollbarAdjust;
  2257.                 END; { with }
  2258.                 InvalRect( growRect );
  2259.             END ELSE BEGIN
  2260.                 TEDeactivate( docTE );
  2261.                 { the controls should be hidden immediately on deactivation: }
  2262.                 HideControl( docVScroll );
  2263.                 HideControl( docHScroll );
  2264.                 { the growbox should be changed immediately on deactivation: }
  2265.                 DrawGrowIcon( window );
  2266.             END; { if }
  2267. END; { DoActivate }
  2268.  
  2269.  
  2270.  
  2271. {$S Main}
  2272. PROCEDURE GetGlobalMouse(VAR mouse: Point);
  2273.  
  2274. {Get the global coordinates of the mouse. When you call OSEventAvail
  2275.  it will return either a pending event or a null event. In either case,
  2276.  the where field of the event record will contain the current position
  2277.  of the mouse in global coordinates and the modifiers field will reflect
  2278.  the current state of the modifiers. Another way to get the global
  2279.  coordinates is to call GetMouse and LocalToGlobal, but that requires
  2280.  being sure that thePort is set to a valid port.}
  2281.  
  2282. VAR
  2283.     event    : EventRecord;
  2284.     
  2285. BEGIN
  2286.     IF OSEventAvail(kNoEvents, event) THEN;    {we aren't interested in any events}
  2287.     mouse := event.where;                    {just the mouse position}
  2288. END;
  2289.  
  2290.  
  2291.  
  2292. {$S Main}
  2293. PROCEDURE AdjustCursor( mouse : Point; region : RgnHandle );
  2294.  
  2295. { Change the cursor's shape, depending on its position. This also calculates a region
  2296.  that includes the cursor for WaitNextEvent. }
  2297.  
  2298. VAR
  2299.     window        : WindowPtr;
  2300.     arrowRgn    : RgnHandle;
  2301.     iBeamRgn    : RgnHandle;
  2302.     iBeamRect    : Rect;
  2303.  
  2304. BEGIN { AdjustCursor }
  2305.     window := FrontWindow; { we only adjust the cursor when we are in front }
  2306.     IF ( NOT gInBackground ) AND ( NOT IsDAWindow( window ) ) THEN BEGIN
  2307.         { calculate regions for different cursor shapes}
  2308.         arrowRgn := NewRgn;
  2309.         iBeamRgn := NewRgn;
  2310.  
  2311.         { start with a big, big rectangular region }
  2312.         SetRectRgn( arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos );
  2313.  
  2314.         { calculate iBeamRgn }
  2315.         IF IsAppWindow( window ) THEN BEGIN
  2316.             iBeamRect := DocumentPeek( window )^.docTE^^.viewRect;
  2317.             SetPort( window ); { make a global version of the viewRect }
  2318.             WITH iBeamRect DO BEGIN
  2319.                 LocalToGlobal( topLeft );
  2320.                 LocalToGlobal( botRight );
  2321.             END; { with }
  2322.             RectRgn( iBeamRgn, iBeamRect );
  2323.             WITH window^.portBits.bounds DO
  2324.                 SetOrigin( -left, -top );
  2325.             SectRgn( iBeamRgn, window^.visRgn, iBeamRgn );
  2326.             SetOrigin( 0, 0 );
  2327.         END; { if }
  2328.  
  2329.         { subtract other regions from arrowRgn }
  2330.         DiffRgn( arrowRgn, iBeamRgn, arrowRgn );
  2331.         
  2332.         {change the cursor and the region parameter}
  2333.         IF PtInRgn( mouse, iBeamRgn ) THEN BEGIN
  2334.             SetCursor( GetCursor( iBeamCursor )^^ );
  2335.             CopyRgn( iBeamRgn, region );
  2336.         END ELSE BEGIN
  2337.             SetCursor( arrow );
  2338.             CopyRgn( arrowRgn, region );
  2339.         END; { if }
  2340.  
  2341.         { get rid of our local regions }
  2342.         DisposeRgn( arrowRgn );
  2343.         DisposeRgn( iBeamRgn );
  2344.     END; { if }
  2345. END; { AdjustCursor }
  2346.  
  2347.  
  2348.  
  2349. {$S Main}
  2350. PROCEDURE DoEvent( event : EventRecord );
  2351.  
  2352. {    Do the right thing for an event. Determine what kind of event it is, and call
  2353.      the appropriate routines. }
  2354. { CHANGES FOR QUILL: call new routines DoDragWindow, DoMenuClose;
  2355.   added kHighLevelEvent case }
  2356.  
  2357. VAR
  2358.     part, err    : INTEGER;
  2359.     window        : WindowPtr;
  2360.     key            : CHAR;
  2361.     ignore        : BOOLEAN;
  2362.     aPoint        : Point;
  2363.  
  2364. BEGIN { DoEvent }
  2365.     CASE event.what OF
  2366.         nullEvent:
  2367.             DoIdle;
  2368.         mouseDown: BEGIN
  2369.         
  2370.             CheckKeyBuffer;
  2371.         
  2372.             part := FindWindow( event.where, window );
  2373.             CASE part OF
  2374.                 
  2375.                 inMenuBar : BEGIN
  2376.                     AdjustMenus;
  2377.                     DoMenuCommand( MenuSelect( event.where ) );
  2378.                 END; { inMenuBar }
  2379.                 
  2380.                 inSysWindow :
  2381.                     SystemClick( event, window );
  2382.                 
  2383.                 inContent :
  2384.                     IF window <> FrontWindow THEN BEGIN
  2385.                     {  wndwIndex := IndexFromWndwPtr(window);
  2386.                       IF wndwIndex <> 0 THEN SendAEMove(wndwIndex,1,kAEBefore);}
  2387.                       MyBringWndwFront(window);
  2388.                         {SelectWindow(window);}
  2389.                         {DoEvent(event);}    {use this line for "do first click"}
  2390.                     END ELSE
  2391.                         DoContentClick( window, event );
  2392.  
  2393.                 inDrag :
  2394.                     DoDragWindow( window, event.where, screenBits.bounds );
  2395.                 
  2396.                 inGrow:
  2397.                     DoGrowWindow( window, event );
  2398.                 
  2399.                 inGoAway:
  2400.                     IF TrackGoAway( window, event.where ) THEN DoMenuClose( window );
  2401.                 
  2402.                 inZoomIn, inZoomOut:
  2403.                 
  2404.                     IF TrackBox(window, event.where, part) THEN
  2405.                         DoZoomWindow( window, part );
  2406.             END; { case }
  2407.         END; { mouseDown }
  2408.         
  2409.         keyDown, autoKey : BEGIN
  2410.             key := CHR( BAnd( event.message, charCodeMask ) );
  2411.             IF BAnd( event.modifiers, cmdKey ) <> 0 THEN BEGIN { Command key down }
  2412.             
  2413.                 CheckKeyBuffer;
  2414.             
  2415.                 IF event.what = keyDown THEN BEGIN
  2416.                     AdjustMenus; { enable/disable/check menu items properly }
  2417.                     DoMenuCommand( MenuKey( key ) );
  2418.                 END; { if }
  2419.             END ELSE
  2420.                 DoKeyDown( event );
  2421.         END; { keyDown } { call DoActivate with the window and... }
  2422.         
  2423.         activateEvt: { TRUE for activate, FALSE for deactivate }
  2424.         BEGIN
  2425.             CheckKeyBuffer;
  2426.             DoActivate( WindowPtr( event.message ), BAND( event.modifiers, activeFlag ) <> 0 );
  2427.         END;
  2428.         
  2429.         updateEvt: { call DoUpdate with the window to update }
  2430.         BEGIN
  2431.             CheckKeyBuffer;
  2432.             DoUpdate( WindowPtr( event.message ) );
  2433.         END;
  2434.             
  2435.         diskEvt:
  2436.         BEGIN
  2437.             CheckKeyBuffer;    { needed here? }
  2438.             IF HiWrd(event.message) <> noErr THEN BEGIN
  2439.                 SetPt(aPoint, kDILeft, kDITop);
  2440.                 err := DIBadMount(aPoint, event.message);
  2441.             END;
  2442.         END;
  2443.  
  2444.         kOSEvent:
  2445.             CASE BAnd(BRotL( event.message, 8 ), $FF ) OF    { high byte of message }
  2446.                 kMouseMovedMessage:
  2447.                     DoIdle; { mouse moved is also an idle event }
  2448.                 
  2449.                 kSuspendResumeMessage: BEGIN
  2450.                     CheckKeyBuffer;
  2451.                     gInBackground := BAnd( event.message, kResumeMask ) = 0;
  2452.                     DoActivate( FrontWindow, NOT gInBackground );
  2453.                 END; { kSuspendResumeMessage }
  2454.         END; 
  2455.         kHighLevelEvent:
  2456.           BEGIN
  2457.             CheckKeyBuffer;
  2458.             DoHighLevelEvent(event);
  2459.           END;
  2460.     END; { case }
  2461. END; { DoEvent }
  2462.  
  2463.  
  2464. {$S Main}
  2465. PROCEDURE EventLoop;
  2466.  
  2467. {Get events forever, and handle them by calling DoEvent.
  2468.  Also call AdjustCursor each time through the loop.}
  2469. { CHANGES FOR QUILL:  initialize gQuitNow to FALSE,
  2470.   and only quit when it's been set to TRUE (by MyTerminate) 
  2471. }
  2472. VAR
  2473.     cursorRgn        : RgnHandle;
  2474.     gotEvent        : BOOLEAN;
  2475.     event            : EventRecord;
  2476.  
  2477. BEGIN
  2478.     cursorRgn := NewRgn;        {we'll pass an empty region to WNE the first time thru}
  2479.     gQuitNow := FALSE;
  2480.     WHILE NOT gQuitNow DO
  2481.       BEGIN
  2482.         IF gHasWaitNextEvent THEN
  2483.             gotEvent := WaitNextEvent(everyEvent, event, GetSleep, cursorRgn)
  2484.         ELSE
  2485.           BEGIN
  2486.             SystemTask;
  2487.             gotEvent := GetNextEvent(everyEvent, event);
  2488.           END;
  2489.         IF gotEvent THEN
  2490.           BEGIN
  2491.             AdjustCursor(event.where, cursorRgn);
  2492.             DoEvent(event);
  2493.           END
  2494.         ELSE DoIdle;
  2495.         AdjustCursor(event.where, cursorRgn);
  2496.       END; { of WHILE }
  2497.       
  2498. END; {EventLoop}
  2499.  
  2500. { NEW ROUTINES FOR QUILL (including major rewrites with new names) }
  2501.  
  2502. {$S QuillNew2}
  2503. FUNCTION AnythingFromListAccessor(wantClass: DescType; container: AEDesc;
  2504.     containerClass: DescType; form: DescType; selectionData: AEDesc;
  2505.     VAR value: AEDesc; theRefCon: LongInt): OSErr;
  2506. { the OSL may return us a list of tokens.  If that's the "container" from
  2507.   which we want to get a property or element, we want to return a corresponding
  2508.   list of tokens for the properties or elements.
  2509.   NOTES:
  2510.   (1) we abort on any error, even if it only involves a single item.  Do we
  2511.   want to be more robust?
  2512.   (2) due to the call to AECallObjectAccessor, this is a (potentially) recursive
  2513.   routine - our list can contain embedded lists.
  2514.   (3) AppleEvents refers to "items" of a list (e.g., AECountItems).  But we're already
  2515.   using "item" as a specific element of text, so we'll have to use a different class
  2516.   name (not cItem) to refer to items in a list.  (That may not come up in this routine;
  2517.   I'm just thinking out loud, sort of.  **CHECK)  We'll still use the word "item" here,
  2518.   though.
  2519. }
  2520. LABEL 9;
  2521. VAR myErr:    OSErr;
  2522.     itemCount:    LongInt;
  2523.     i:            LongInt;
  2524.     thisItem:    AEDesc;
  2525.     myToken:    AEDesc;
  2526. BEGIN
  2527.   myErr := accessorErr;
  2528.   InitSomeDescs(@value,@thisItem,@myToken,NIL,NIL);
  2529.   
  2530.   { **HACK - special-case cListElement }
  2531.   IF wantClass = cListElem THEN
  2532.     BEGIN
  2533.       myErr := ElemFromAnythingAccessor(wantClass,container,containerClass,form,selectionData,value,theRefCon);
  2534.       GOTO 9;
  2535.     END;
  2536.   
  2537.   { count the items in the list }
  2538.   IF CatchErr(   AECountItems(container,itemCount) , 21213 , myErr ) THEN GOTO 9;
  2539.   
  2540.   { create the result list }
  2541.   IF CatchErr(   AECreateList(NIL,0,FALSE,value) , 21214 , myErr ) THEN GOTO 9;
  2542.   
  2543.   IF itemCount = 0 THEN GOTO 9;    { empty list - we're done }
  2544.   
  2545.   { loop through the items }
  2546.   FOR i := 1 TO itemCount DO
  2547.     BEGIN
  2548.       { get the item }
  2549.       IF CatchErr(   AEGetNthDesc(container,i,typeWildCard,gReturnedKeywd,thisItem) , 21215 ,
  2550.           myErr ) THEN GOTO 9;
  2551.           
  2552.       { using the given selection data, and the container item that was contained, get }
  2553.       { a token for the corresponding property or element                              }
  2554.       { **CHECK on inputs to AECallObjectAccessor, particularly container class        }
  2555.       IF CatchErr(   AECallObjectAccessor(wantClass,thisItem,thisItem.descriptorType,form,
  2556.           selectionData,myToken) , 21216 , myErr ) THEN GOTO 9;
  2557.           
  2558.       { put it in the list }
  2559.       IF CatchErr(   AEPutDesc(value,i,myToken) , 21217 , myErr ) THEN GOTO 9;
  2560.       
  2561.       { dispose of item and token }
  2562.       IF CatchErr(   DisposeSomeDescs(@thisItem,@myToken,NIL,NIL,NIL) , 21218 , myErr ) THEN GOTO 9;
  2563.       InitSomeDescs(@thisItem,@myToken,NIL,NIL,NIL);    { just for neatness, almost certainly unnecessary - **CHECK }
  2564.     END;
  2565.     
  2566. 9:    { finish up }
  2567.   IF myErr <> noErr THEN gTempBool := CheckErr(   AEDisposeDesc(value) , 21219 );
  2568.   gTempBool := CheckErr(   DisposeSomeDescs(@thisItem,@myToken,NIL,NIL,NIL) , 21220 );
  2569.   
  2570.   AnythingFromListAccessor := myErr;
  2571. END;    { AnythingFromListAccessor }
  2572.  
  2573.  
  2574. {$S QuillNew }
  2575. FUNCTION AskAboutSave(name: Str255; VAR saveFlag: BOOLEAN): BOOLEAN;
  2576. { ask the user if we should save or not before closing; return response
  2577.   in saveFlag.  Also return (as function value) whether the user 
  2578.   cancelled or not.
  2579.   INPUTS:    wndwTitle    name of document we're asking about (used in dialog)
  2580.               saveFlag    result VAR for response - TRUE if save, FALSE
  2581.                         if don't save
  2582.   OUTPUTS:    FALSE if the user cancelled, TRUE o.w.
  2583.   ERRORS:
  2584.   SIDE EFFECTS:
  2585.   NOTES:    technically, saveFlag is undefined if the user cancels
  2586.               (although we'll set it to FALSE in that case)
  2587. }
  2588. VAR itemHit:    INTEGER;
  2589. BEGIN
  2590.   AskAboutSave := FALSE;
  2591.   saveFlag := FALSE;
  2592.   
  2593.   itemHit := AskUser(Concat('Save changes to "',name,'" before closing?"'));
  2594.   IF itemHit = 3 THEN EXIT(AskAboutSave);    { user cancelled (3 is 'cancel') }
  2595.   
  2596.   saveFlag := (itemHit = 1);            { 1 is 'yes', 2 is 'no' }
  2597.   AskAboutSave := TRUE;
  2598. END;
  2599.  
  2600.  
  2601. {$S QuillNew }
  2602. FUNCTION AskBeforeClosing(window: WindowPtr; VAR saveFlag: BOOLEAN;
  2603.     VAR docFileGood: BOOLEAN; VAR fileSpec: FSSpec):    BOOLEAN;
  2604. { ask the user if he wants to save changes before closing.  If yes,
  2605.   AND the window doc has a valid file spec attached to it, return
  2606.   the file spec; if yes, but no valid file spec, ask the user to 
  2607.   specify a file, and return that file spec.  Also give the user
  2608.   a chance to cancel the close whenever he's responding to a dialog.
  2609.   INPUTS:    window        ptr to the window in question
  2610.               saveFlag    result VAR - TRUE if the user wants to
  2611.                         save, FALSE o.w. (undefined if user cancels,
  2612.                         although we'll return FALSE in that case)
  2613.             docFileGood    result VAR - TRUE if docFile is a valid file 
  2614.                         spec (vRefNum <> badVRefNum), FALSE otherwise. 
  2615.                         This is just FYI; sometimes it's useful to know
  2616.                         where fileSpec came from (window doc or user responses).
  2617.                         (docFileGood is undefined if the user cancels or doesn't 
  2618.                         want to save, but we'll set it to FALSE in those cases)
  2619.             fileSpec    result VAR for the file to be saved to
  2620.                         (undefined if the user cancels or doesn't
  2621.                         want to save, although we'll mark it as
  2622.                         invalid in that case)
  2623.   OUTPUTS:    TRUE if the user doesn't cancel (regardless of whether
  2624.               he saves or not), FALSE if user cancels
  2625.   ERRORS:
  2626.   SIDE EFFECTS:
  2627.   NOTES:    this routine does NOT:  check the window doc dirtyFlag;
  2628.               call AEInteractWithUser; save the doc itself; close the
  2629.             window itself.  That's all up to the caller
  2630. }
  2631. VAR wndwTitle:    Str255;
  2632. BEGIN
  2633.   AskBeforeClosing := FALSE;
  2634.   saveFlag := FALSE;
  2635.   docFileGood := FALSE;
  2636.   fileSpec.vRefNum := badVRefNum;
  2637.   
  2638.   GetWTitle(window,wndwTitle);
  2639.   
  2640.   IF NOT AskAboutSave(wndwTitle,saveFlag) THEN EXIT(AskBeforeClosing);    { user cancelled }
  2641.   
  2642.   IF saveFlag THEN
  2643.     BEGIN
  2644.       { user wants to save - do we have a file? }
  2645.       docFileGood := DocumentPeek(window)^.docFile.vRefNum <> badVRefNum;
  2646.       IF docFileGood THEN fileSpec := DocumentPeek(window)^.docFile { good file spec in window doc }
  2647.       ELSE
  2648.         BEGIN    { we don't have a file - ask for one }
  2649.           IF NOT AskForFile(wndwTitle,fileSpec) THEN
  2650.             BEGIN
  2651.               { user cancelled }
  2652.               saveFlag := FALSE;    { just for neatness }
  2653.               EXIT(AskBeforeClosing);
  2654.             END;    { of user cancelling from AskForFile }
  2655.         END;    { of asking for file }
  2656.     END;    { of user asking to save }
  2657.     
  2658.   { if we got this far, we're fine }
  2659.   AskBeforeClosing := TRUE;
  2660. END;    { AskBeforeClosing }
  2661.  
  2662.  
  2663. {$S QuillNew }
  2664. FUNCTION AskForFile(name: Str255; VAR fileSpec: FSSpec):  BOOLEAN;
  2665. { ask the user to pick a file to save a document to.  Return the
  2666.   file spec, and also return (as function result) whether the user
  2667.   cancelled or not.
  2668.   INPUTS:    name        default name for file (used in StandardFile dialog)
  2669.               fileSpec    result VAR for chosen file
  2670.   OUTPUTS:    FALSE if the user cancelled, TRUE o.w.
  2671.   ERRORS:
  2672.   SIDE EFFECTS:
  2673.   NOTES:    if user cancels, fileSpec is undefined (although we'll
  2674.               set its vRefNum to badVRefNum in that case, for neatness)
  2675. }
  2676. VAR mySFReply:    StandardFileReply;
  2677. BEGIN
  2678.   AskForFile := FALSE;
  2679.   fileSpec.vRefNum := badVRefNum;
  2680.   
  2681.   StandardPutFile(Concat('Save "',name,'" as:  '),name,mySFReply);
  2682.   WITH mySFReply DO
  2683.     BEGIN
  2684.       IF NOT sfGood THEN EXIT(AskForFile);    { user cancelled }
  2685.       fileSpec := sfFile;
  2686.     END;
  2687.  
  2688.   AskForFile := TRUE;
  2689. END;
  2690.  
  2691. {$S QuillNew}
  2692. FUNCTION AskUser( question: Str255 ): INTEGER;
  2693.  
  2694. {  put up an Alert to ask the user a question,
  2695.    with possible responses yes, no, or cancel
  2696.    
  2697.    INPUTS:    question        text of the question
  2698.    OUTPUTS:    1 for yes, 2 for no, 3 for cancel
  2699.    ERRORS:
  2700.    SIDE EFFECTS:
  2701. }
  2702. BEGIN { AskUser }
  2703.   SetCursor( arrow );
  2704.   ParamText(question, '', '', '');
  2705.   AskUser := Alert( rYesOrNo, NIL );
  2706. END; { AskUser }
  2707.  
  2708. {$S QuillNew}
  2709. FUNCTION BackWindow:  WindowPtr;
  2710. { returns a ptr to the last window in the back-to-front
  2711.   ordering.  If there are nu current windows, returns NIL.
  2712.   INPUTS:    none
  2713.   OUTPUTS:    ptr to last window (NIL if no windows)
  2714. }
  2715. LABEL 9;
  2716. VAR window:        WindowPtr;
  2717.     nextWndw:    WindowPtr;
  2718. BEGIN
  2719.   window := FrontWindow;
  2720.   IF window = NIL THEN GOTO 9;    { no windows - go finish up }
  2721.   WHILE TRUE DO        { repeat forever, sort of }
  2722.     BEGIN
  2723.       nextWndw := WindowPtr(WindowPeek(window)^.nextWindow);
  2724.       IF nextWndw = NIL THEN GOTO 9;    { got last window, it's in "window" - go finish up }
  2725.       window := nextWndw;    { try the next one }
  2726.     END;
  2727.     
  2728. 9:    { finish up }
  2729.   BackWindow := window;
  2730. END;    { BackWindow }
  2731.  
  2732.  
  2733. {$S QuillNew }
  2734. FUNCTION BoolToStr(theBool: BOOLEAN): Str15;
  2735. BEGIN
  2736.   IF theBool THEN BoolToStr := 'TRUE' ELSE BoolToStr := 'FALSE';
  2737. END;    { BoolToStr }
  2738.  
  2739. {$S QuillNew}
  2740. FUNCTION CatchErr(theErr: OSErr; placeNum: INTEGER; VAR holdErr: OSErr):  BOOLEAN;
  2741. { if theErr <> noErr, then put up an error alert and return TRUE; o.w. return 
  2742.   FALSE (no alert).  In either case, return theErr in holdErr for future use.
  2743.   This is just like CheckErr except that it also saves the err; see CheckErr and
  2744.   DoMyErr for more details.
  2745.   INPUTS:    theErr            potential error to be checked and reported
  2746.               placeNum        number to mark actual place of error in code; should be unique
  2747.             VAR holdErr        variable to store error number
  2748.   OUTPUTS:    TRUE if theErr is an error (not noErr), FALSE o.w.
  2749.   ERRORS:
  2750.   SIDE EFFECTS:    will put up error alert if theErr <> noErr
  2751. }
  2752. BEGIN
  2753.   holdErr := theErr;
  2754.   CatchErr := CheckErr(theErr,placeNum);
  2755. END;  { CatchErr }
  2756.  
  2757. {$S QuillNew}
  2758. PROCEDURE CheckKeyBuffer;
  2759. { check to see if the key buffer is empty and, if
  2760.   it's not, ship it off in a Set Data event so we
  2761.   can record the typing represented by it.  Then
  2762.   clear the buffer.
  2763.   INPUTS:    none
  2764.   OUTPUTS:    none
  2765.   NOTES:    (1) very preliminary, especially the error-handling
  2766.               (2) IMPORTANT: we ship out the characters FOR RECORDING
  2767.             PURPOSES ONLY - we've already handled the changing of
  2768.             text in real-time, when the user did the typing
  2769.             ( **CHECK - Ed, how do we mark things "for recording only"?)
  2770.             10/03/91    BHM        experimental change to use "smart" recording (when feasible)
  2771. }
  2772. LABEL 9;
  2773. VAR tempErr:        OSErr;
  2774.     textDesc:        AEDesc;
  2775.     wndwIndex:        INTEGER;
  2776.     origSelObj:        AEDesc;
  2777.     myAppleEvent:    AppleEvent;
  2778.     defReply:        AppleEvent;
  2779. BEGIN
  2780.   { fast exit if key buffer empty }
  2781.   IF keyBuffer.bufEmpty THEN EXIT(CheckKeyBuffer);
  2782.   
  2783.   { we've got some keystrokes to ship out }
  2784.   { NOTE:  due to the special handling of Delete characters, we may in fact       }
  2785.   { have no actual characters to send; the Delete characters may have cancelled   }
  2786.   { the normal characters.  But we still have to record the deletion of the       } 
  2787.   { selection (which would still occur even in the case of this "cancelling"),    }
  2788.   { so we still have to send a Set Data event.                                    }
  2789.   
  2790.   InitSomeDescs(@textDesc,@origSelObj,@myAppleEvent,@defReply,NIL);
  2791.   
  2792.   WITH keyBuffer DO
  2793.     BEGIN
  2794.       
  2795.       { create a descriptor for text in the buffer }
  2796.       HLock(Handle(bufChars));
  2797.       tempErr := AECreateDesc(typeChar,Handle(bufChars)^,bufCharCount,textDesc);
  2798.       HUnlock(Handle(bufChars));
  2799.       IF CheckErr(   tempErr , 19313 ) THEN GOTO 9;
  2800.       
  2801.       { now do some work on the selection AS IT WAS WHEN THE USER STARTED TYPING }
  2802.       
  2803.       { **CHECK - EXPERIMENTAL - 10/3/91: }
  2804.       { If there are no "uncancelled" Delete chars, then the selection obj recorded }
  2805.       { when we started buffering is good - and it uses "smart" recording           }
  2806.       
  2807.       IF bufDelCount = 0 THEN
  2808.         BEGIN
  2809.           { I'll take the easy way out and just copy it over, for now }
  2810.           IF CheckErr(   AEDuplicateDesc(bufDesc,origSelObj) , 19321 ) THEN GOTO 9;
  2811.         END
  2812.         
  2813.       ELSE
  2814.       
  2815.         BEGIN
  2816.           { uncancelled Deletes case }
  2817.       
  2818.       { first, adjust for "uncancelled" Delete chars (if any)                    }
  2819.       bufSelStart := bufSelStart - bufDelCount;
  2820.       IF bufSelStart < 0 THEN bufSelStart := 0;    { can't have a negative char position }
  2821.       
  2822.       { now make on object for the old (but adjusted) selection }
  2823.       
  2824.       wndwIndex := IndexFromWndwPtr(bufWndw);
  2825.       { **CHECK for 0? or, for that matter - check for 1 (it should always be 1 . . .) }
  2826.       IF bufSelStart = bufSelEnd THEN
  2827.         BEGIN
  2828.           IF CheckErr(   MakeSpotObj(wndwIndex,bufSelStart+1,origSelObj) , 19314 ) THEN GOTO 9;
  2829.         END
  2830.       ELSE
  2831.         BEGIN
  2832.           IF CheckErr(   MakeTextRangeObj(wndwIndex,bufSelStart+1,bufSelEnd,origSelObj) , 19315 ) THEN GOTO 9;
  2833.         END;
  2834.         
  2835.         END;    { uncancelled Deletes case }
  2836.         
  2837.       { NOTE:  the "+1's" are in there because selections are internally represented starting from 0, but }
  2838.       { objects are counted starting from 1                                                               }
  2839.     END;    { of WITH keyBuffer }
  2840.     
  2841.   { create the AppleEvent }
  2842.   IF CheckErr(   AECreateAppleEvent(kAECoreSuite,kAESetData,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,
  2843.       myAppleEvent) , 19316 ) THEN GOTO 9;
  2844.       
  2845.   { add the direct object }
  2846.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyDirectObject,origSelObj) , 19317 ) THEN GOTO 9;
  2847.   
  2848.   { add the data }
  2849.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyAEData,textDesc) , 19318 ) THEN GOTO 9;
  2850.   
  2851.   { **CHECK - must set bufEmpty = TRUE before sending the Set Data        }
  2852.   { event, because the event itself will set off this routine . . . ??!*? }
  2853.   
  2854.   keyBuffer.bufEmpty := TRUE;
  2855.   
  2856.   { send the event }
  2857.   gTempBool := CheckErr(   AESend(myAppleEvent,defReply,kAENoReply+kAEAlwaysInteract+kAEDontExecute,kAENormalPriority,
  2858.       kAEDefaultTimeOut,NIL,NIL) , 19319 );
  2859.       
  2860.     {  ShowTyping(textDesc);}
  2861.       
  2862. 9:    { finish up }
  2863.  
  2864.   gTempBool := CheckErr(   DisposeSomeDescs(@textDesc,@origSelObj,@myAppleEvent,@defReply,NIL) , 19320 );
  2865.   
  2866.   ResetKeyBuffer;
  2867. END;    { CheckKeyBuffer }
  2868.  
  2869.  
  2870. {$S QuillNew}
  2871. FUNCTION CheckErr(theErr: OSErr; placeNum: INTEGER):  BOOLEAN;
  2872. { if theErr <> noErr, then put up an error alert (including err num
  2873.   and placeNum) and return TRUE; o.w. just return FALSE (with no alert).  This 
  2874.   is meant to be used with error-returning function calls (e.g., all AE routines) 
  2875.   in the first parameter.  See DoMyErr for more details.
  2876.   INPUTS:    theErr            potential error to be checked and reported
  2877.               placeNum        number to mark actual place of error in code; should be unique
  2878.   OUTPUTS:    TRUE if theErr is an error (not noErr), FALSE o.w.
  2879.   ERRORS:
  2880.   SIDE EFFECTS:    will put up error alert if theErr <> noErr
  2881. }
  2882. BEGIN
  2883.   CheckErr := FALSE;
  2884.   IF theErr <> noErr THEN
  2885.     BEGIN
  2886.       DoMyErr(theErr,placeNum);
  2887.       CheckErr := TRUE;
  2888.     END;
  2889. END; { CheckErr }
  2890.  
  2891. {$S QuillNew}
  2892. PROCEDURE CleanWindow(window: WindowPtr);
  2893. { mark the given window as not dirty
  2894.   INPUTS:    window        ptr to the window 
  2895.   OUPUTS:    none
  2896. }
  2897. BEGIN
  2898.   DocumentPeek(window)^.dirtyFlag := FALSE;
  2899. END;  { CleanWindow }
  2900.  
  2901. {$S QuillNew }
  2902. FUNCTION CloseAllAskUser(VAR userCancelled: BOOLEAN): OSErr;
  2903. { close the windows one at a time.  For each dirty window,
  2904.   ask the user if she wants to save; also give her a chance
  2905.   to cancel out.  Call AEInteractWithUser before putting up
  2906.   a dialog; if interaction is impossible, abort with 
  2907.   appropriate error code
  2908.   INPUTS:    userCancelled        result VAR - TRUE if the user
  2909.                                   cancelled, FALSE o.w. (undefined
  2910.                                 if call fails, but we'll set it 
  2911.                                 to FALSE in that case)
  2912.   OUTPUTS:    error number (noErr if none).  User cancellation
  2913.               is NOT an error.
  2914.   ERRORS:
  2915.   SIDE EFFECTS:
  2916. }
  2917. LABEL 8,9;
  2918. VAR myErr:            OSErr;
  2919.     window:            WindowPtr;
  2920.     saveFlag:        BOOLEAN;
  2921.     docFileGood:    BOOLEAN;
  2922.     fileSpec:        FSSpec;
  2923. BEGIN
  2924.   myErr := genericErr;
  2925.   userCancelled := FALSE;
  2926.   
  2927.   window := FrontWindow;
  2928.   WHILE window <> NIL DO
  2929.     BEGIN
  2930.       IF WindowIsDirty(window) THEN
  2931.         BEGIN
  2932.           { dirty window - should we save? }
  2933.           IF CatchErr(   AEInteractWithUser(kNoTimeOut,NIL,NIL) , 8513 , myErr )
  2934.               THEN GOTO 9;    { couldn't interact - go set function value }
  2935.           
  2936.           { we're IN-TER-ACT-ING!!! }
  2937.           userCancelled := NOT AskBeforeClosing(window,saveFlag,docFileGood,fileSpec);
  2938.           IF userCancelled THEN GOTO 8;        { noErr exit }
  2939.             
  2940.           IF saveFlag THEN
  2941.               IF CatchErr(   GetFileAndSaveWndw(window,TRUE,fileSpec) , 8514 , myErr )
  2942.                   THEN GOTO 9;    { trouble with the save }
  2943.         END;    { of dirty window }
  2944.       ShutTheWindow(window);
  2945.       window := WindowPtr(WindowPeek(window)^.nextWindow);
  2946.     END;    { of WHILE loop }
  2947.     
  2948.   { everything looks fine }
  2949. 8:    { noErr exit }
  2950.   myErr := noErr;
  2951.   
  2952. 9:    { set function value }
  2953.   CloseAllAskUser := myErr;
  2954. END;    { CloseAllAskUser }
  2955.  
  2956. {$S QuillNew }
  2957. PROCEDURE CloseAllNoSave;
  2958. { close all windows, don't save any of them
  2959.   INPUTS:    none
  2960.   OUTPUTS:    none
  2961.   ERRORS:
  2962.   SIDE EFFECTS:
  2963. }
  2964. VAR window:    WindowPtr;
  2965. BEGIN
  2966.   window := FrontWindow;
  2967.   WHILE window <> NIL DO
  2968.     BEGIN
  2969.       ShutTheWindow(window);
  2970.       window := WindowPtr(WindowPeek(window)^.nextWindow);
  2971.     END;
  2972. END;    { CloseAllNoSave }
  2973.  
  2974. {$S QuillNew }
  2975. FUNCTION CloseAllWithSave: OSErr;
  2976. { close all windows, save all the dirty ones - don't
  2977.   interact with user.  We use GetFileAndSaveWndw, which
  2978.   (in this case) first tries the window's docFile, if
  2979.   it's valid, and then tries to concoct a file from
  2980.   the window title and the current default volume
  2981.   and path.
  2982.   INPUTS:    none
  2983.   OUTPUTS:    error code (noErr if none) - file-and-mem
  2984.               problems, generally
  2985.   ERRORS:
  2986.   SIDE EFFECTS:
  2987. }
  2988. LABEL 9;
  2989. VAR myErr:        OSErr;
  2990.     window:        WindowPtr;
  2991.     fileSpec:    FSSpec;
  2992. BEGIN
  2993.   myErr := genericErr;
  2994.   window := FrontWindow;
  2995.   WHILE window <> NIL DO
  2996.     BEGIN
  2997.       IF WindowIsDirty(window) THEN 
  2998.         IF CatchErr(   GetFileAndSaveWndw(window,FALSE,fileSpec) , 8414 , myErr ) THEN
  2999.             GOTO 9;    { save failed - go set function value }
  3000.       ShutTheWindow(window);
  3001.       window := WindowPtr(WindowPeek(window)^.nextWindow);
  3002.     END;
  3003.     
  3004.   { everything looks fine }
  3005.   myErr := noErr;
  3006.   
  3007. 9:    { set function value }
  3008.   CloseAllWithSave := myErr;
  3009. END;    { CloseAllWithSave }
  3010.  
  3011. {$S QuillNew2}
  3012. FUNCTION CloseToken(theToken: AEDesc; saveOpt: DescType; gotDestFile: BOOLEAN;
  3013.     destFile: FSSpec): OSErr;
  3014. { this routine takes a single token (not a list) and closes the object it
  3015.   represents.  Right now we only know how to close windows and documents.
  3016.   INPUTS:    theToken        token representing the object to be closed
  3017.             saveOpt            parameter describing whether or not to save "dirty"
  3018.                             object:  kAEYes (save), kAENo (don't save), or 
  3019.                             kAEAsk (ask user)
  3020.             gotDestFile        TRUE if file to be saved to is specified, FALSE o.w.
  3021.             destFile        a file to save the document to
  3022.   OUTPUTS:    error code (noErr if none)
  3023.   NOTES:    (1) if saveOpt is not kAEYes, then gotDestFile and destFile are ignored;
  3024.               if gotDestFile is FALSE, then destFile is ignored.
  3025.             (2) we do not validate saveOpt here; that should be done higher up
  3026. }
  3027. LABEL 9;
  3028. VAR myErr:        OSErr;
  3029.     myWndw:        WindowPtr;
  3030.     saveFlag:    BOOLEAN;
  3031.     myFSS:        FSSpec;
  3032. BEGIN
  3033.   myErr := genericErr;
  3034.   
  3035.   { token must be window or doc }
  3036.   IF (theToken.descriptorType <> typeMyWndw) & (theToken.descriptorType <> typeMyDoc) THEN
  3037.     BEGIN
  3038.       gTempBool := CatchErr(   errAEWrongDataType , 24013 , myErr );
  3039.       GOTO 9;
  3040.     END;
  3041.     
  3042.   { get the window/doc }
  3043.   IF CatchErr(   MyAECoerceDescPtr(theToken,typeWildCard,@myWndw,SizeOf(myWndw),gActSize) , 
  3044.       24014 , myErr ) THEN GOTO 9; 
  3045.       
  3046.   { if it's dirty, you may have to save }
  3047.   IF WindowIsDirty(myWndw) & (saveOpt <> kAENo) THEN
  3048.     BEGIN
  3049.     
  3050.       IF saveOpt = kAEAsk THEN
  3051.         BEGIN
  3052.           { have to ask user about saving }
  3053.           IF CatchErr(   AEInteractWithUser(kNoTimeOut,NIL,NIL) , 24015 , myErr ) THEN GOTO 9; 
  3054.           IF NOT AskBeforeClosing(myWndw,saveFlag,gTempBool,myFSS) THEN
  3055.             BEGIN
  3056.               { user cancelled }
  3057.               myErr := errAEUserCancelled;
  3058.               GOTO 9;
  3059.             END;
  3060.           IF saveFlag THEN
  3061.               IF CatchErr(   GetFileAndSaveWndw(myWndw,TRUE,myFSS) , 24016 , myErr ) Then GOTO 9;    { trouble with the save }
  3062.         END    { of kAEAsk case }
  3063.         
  3064.       ELSE IF saveOpt = kAEYes THEN
  3065.         BEGIN
  3066.           { save, without bothering the user }
  3067.           IF CatchErr(   GetFileAndSaveWndw(myWndw,gotDestFile,destFile) , 24017 , myErr ) THEN GOTO 9;
  3068.         END;    { of kAEYes case }
  3069.     
  3070.     END;    { of having to save the window }
  3071.     
  3072.   { now shut it }
  3073.   ShutTheWindow(myWndw);
  3074.   
  3075. 9:
  3076.   CloseToken := myErr;
  3077. END;    { CloseToken }
  3078.  
  3079. {$S QuillNew2}
  3080. FUNCTION CloseTokenList(theList: AEDesc; saveOpt: DescType; gotDestFile: BOOLEAN;
  3081.     destFile: FSSpec): OSErr;
  3082. { this routine takes a list of tokens (or, more precisely, whose ultimate
  3083.   nodes are tokens; we permit lists of lists, etc.), and closes everything
  3084.   on the list.  Actually, it just walks through the list and, when it gets
  3085.   to tokens, passes them to CloseToken.
  3086.   The input parameters are passed unchanged to CloseToken; see that routine 
  3087.   for descriptions.  The gotDestFile and destFile parameters don't really
  3088.   make much sense for a list (you would wind up saving everything in the
  3089.   list to the same destFile); perhaps in the future we'll permit a list
  3090.   of dest files.
  3091.   If we hit an error at any point, we abort the operation; we don't try
  3092.   to continue with other items in the list.
  3093.   
  3094.   INPUTS:    see CloseToken
  3095.   OUTPUTS:    error code (noErr if none)
  3096. }
  3097. LABEL 9;
  3098. VAR    myErr:        OSErr; 
  3099.     itemCount:    LongInt;
  3100.     i:            LongInt;
  3101.     thisItem:    AEDesc;
  3102. BEGIN
  3103.   myErr := genericErr;
  3104.   thisItem := gNullDesc;
  3105.   
  3106.   IF CatchErr(   AECountItems(theList,itemCount) , 23013 , myErr ) THEN GOTO 9;
  3107.   IF itemCount = 0 THEN GOTO 9;    { empty list, we're done }
  3108.   
  3109.   { loop through the items }
  3110.   FOR i := 1 TO itemCount DO
  3111.     BEGIN
  3112.       { get the item }
  3113.       IF CatchErr(   AEGetNthDesc(theList,i,typeWildCard,gReturnedKeywd,thisItem) , 23014 ,
  3114.           myErr ) THEN GOTO 9;
  3115.           
  3116.       { dispatch on list vs. non-list }
  3117.       IF thisItem.descriptorType = typeAEList THEN
  3118.         BEGIN
  3119.           IF CatchErr(   CloseTokenList(thisItem,saveOpt,gotDestFile,destFile) , 23015 , myErr )
  3120.               THEN GOTO 9;
  3121.         END
  3122.       ELSE
  3123.         BEGIN
  3124.           IF CatchErr(   CloseToken(thisItem,saveOpt,gotDestFile,destFile) , 23016 , myErr )
  3125.               THEN GOTO 9;
  3126.         END;
  3127.         
  3128.       { dispose of item }
  3129.       gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 23017 );
  3130.       thisItem := gNullDesc;
  3131.     END;    { FOR loop }
  3132.     
  3133. 9:
  3134.   gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 23018 );
  3135.   CloseTokenList := myErr;
  3136. END;    { CloseTokenList }
  3137.  
  3138.  
  3139. {$S QuillNew2}
  3140. FUNCTION CoerceListOrValToTextStyles(theAEDesc: AEDesc; toType: DescType;
  3141.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;
  3142. { this takes a list, presumably of style item constants, and creates
  3143.   a style desc (of typeTextStyles) that has that list for its "on"
  3144.   styles and an empty list for the "off" styles; this is convenient
  3145.   when you want to say "set the style of some text to [bold, underline]"
  3146.   and not specify the full style desc.  It does no validity checking;
  3147.   if the list is not valid, the problem will get caught when any routine
  3148.   tries to use the resulting style desc.
  3149.   
  3150.   The routine will also take a single enumerated value (presumably a
  3151.   style item constant), which it coerces to a single-item list and then
  3152.   to a style desc.  Again, no validity checking is done.
  3153.   
  3154.   kAEPlain is a valid style item const here.
  3155. }
  3156. LABEL 9;
  3157. VAR myErr:        OSErr;
  3158.     newDesc:    AEDesc;
  3159.     listDesc:    AEDesc;    { doesn't need to be initialized or disposed - it's a "pure copy" }
  3160.     styleRec:    AEDesc;
  3161.     offList:    AEDesc;
  3162. BEGIN
  3163.   myErr := genericErr;
  3164.   InitSomeDescs(@result,@styleRec,@offList,@newDesc,NIL);
  3165.   
  3166.   IF theAEDesc.descriptorType <> typeAEList THEN
  3167.     BEGIN
  3168.       { must be enumerated value; coerce to list }
  3169.       IF CheckErr(   AECoerceDesc(theAEDesc,typeAEList,newDesc) , 22613 ) THEN GOTO 9;
  3170.       listDesc := newDesc;
  3171.     END
  3172.   ELSE listDesc := theAEDesc;    { CAREFUL! - don't dispose of listDesc! }
  3173.   
  3174.   { create the record for text styles desc }
  3175.   IF CatchErr(   AECreateList(NIL,0,TRUE,styleRec) , 22613 , myErr ) THEN GOTO 9;
  3176.   
  3177.   { attach this list }
  3178.   IF CatchErr(   AEPutKeyDesc(styleRec,keyAEOnStyles,theAEDesc) , 22614 , myErr ) THEN GOTO 9;
  3179.   
  3180.   { create empty list for "off" }
  3181.   IF CatchErr(   AECreateList(NIL,0,FALSE,offList) , 22615 , myErr ) THEN GOTO 9;
  3182.   
  3183.   { attach it }
  3184.   IF CatchErr(   AEPutKeyDesc(styleRec,keyAEOffStyles,offList) , 22616 , myErr ) THEN GOTO 9;
  3185.   
  3186.   { coerce record to typeTextStyles }
  3187.   gTempBool := CatchErr(   AECoerceDesc(styleRec,typeTextStyles,result) , 22617 , myErr);
  3188.   
  3189. 9:
  3190.   gTempBool := CheckErr(   DisposeSomeDescs(@styleRec,@offList,@newDesc,NIL,NIL) , 22618 );
  3191.   
  3192.   CoerceListOrValToTextStyles := myErr;
  3193. END;    { CoerceListOrValToTextStyles }
  3194.  
  3195. {$S QuillNew2}
  3196. FUNCTION CoerceMyDocToMyWndw(theAEDesc: AEDesc; toType: DescType; 
  3197.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;
  3198. { we can't make docs and windows EXACTLY the same because pClass
  3199.   is different for them (and there may be one or two other things
  3200.   that come along, too) - but generally we would like to let someone
  3201.   ask for a typeMyWndw regardless of whether we started from cWindow
  3202.   or cDocument
  3203. }
  3204. LABEL 9;
  3205. VAR myErr:    OSErr;
  3206. BEGIN
  3207.   myErr := genericErr;
  3208.   result := gNullDesc;
  3209.   IF CatchErr(   AEDuplicateDesc(theAEDesc,result) , 21413 , myErr ) THEN GOTO 9;
  3210.   result.descriptorType := typeMyWndw;
  3211. 9:
  3212.   CoerceMyDocToMyWndw := myErr;
  3213. END;    { CoerceMyDocToMyWndw }
  3214.  
  3215. {$S QuillNew}
  3216. FUNCTION CoerceMyTextToStylText(theAEDesc: AEDesc; toType: DescType;
  3217.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;
  3218. LABEL 9;
  3219. VAR myErr:    OSErr;
  3220.     myText:    TextToken;
  3221. BEGIN
  3222.   myErr := genericErr;
  3223.   result := gNullDesc;
  3224.   IF CatchErr(   MyAECoerceDescPtr(theAEDesc,typeMyText,@myText,SizeOf(myText),gActSize) , 17313 , myErr )
  3225.       THEN GOTO 9;
  3226.   gTempBool := CatchErr(   MakeStylTextDesc(myText,result) , 17314 , myErr);
  3227. 9:
  3228.   CoerceMyTextToStylText := myErr;
  3229. END;    { CoerceMyTextToStylText }
  3230.  
  3231.  
  3232.  
  3233. {$S QuillNew}
  3234. FUNCTION CoerceObjToAnything(theAEDesc: AEDesc; toType: DescType;
  3235.     handlerRefCon: LongInt; VAR result:  AEDesc): OSErr;
  3236. LABEL 9;
  3237. VAR myErr:        OSErr;
  3238.     objDesc:    AEDesc;
  3239. BEGIN
  3240.   myErr := errAECoercionFail;
  3241.   InitSomeDescs(@result,@objDesc,NIL,NIL,NIL);
  3242.   
  3243.   { check a type for robustness' sake }
  3244.   IF theAEDesc.descriptorType <> typeObjectSpecifier THEN
  3245.     BEGIN
  3246.       gTempBool := CatchErr(   errAEWrongDataType , 1813 , myErr );
  3247.       GOTO 9;
  3248.     END;
  3249.   
  3250.   { resolve the object specifier }
  3251.   IF QuietCatchErr(   AEResolve(theAEDesc,kAEIDoMinimum,objDesc) , myErr )
  3252.       THEN GOTO 9;
  3253.   { hopefully it's the right type by now, but we'll give it a nudge }
  3254.   IF QuietCatchErr(   AECoerceDesc(objDesc,toType,result) , myErr )
  3255.       THEN GOTO 9;
  3256.   { looks good to me }
  3257.   myErr := noErr;
  3258.   
  3259. 9:    { finish up }
  3260.   gTempBool := CheckErr(   AEDisposeDesc(objDesc) , 1814 );
  3261.   
  3262.   { NOTE:  even if myErr <> noErr, we don't have to dispose of result
  3263.     because nothing after result is created can generate an error.  Of
  3264.     course, if myErr = noErr, then you CERTAINLY don't want to dispose
  3265.     of result; you want to return it. }
  3266.     
  3267.   CoerceObjToAnything := myErr;
  3268. END;    { CoerceObjToAnything }
  3269.  
  3270. {$S QuillNew}
  3271. FUNCTION CoerceStylTextToText(theAEDesc: AEDesc; toType: DescType;
  3272.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;
  3273. LABEL 9;
  3274. VAR myErr:        OSErr;
  3275.     newDesc:    AEDesc;
  3276. BEGIN
  3277.   myErr := errAECoercionFail;
  3278.   newDesc := gNullDesc;
  3279.   { some checks for robustness' sake }
  3280.   IF theAEDesc.descriptorType <> typeStyledText THEN
  3281.     BEGIN
  3282.       gTempBool := CatchErr(   errAEWrongDataType , 13413 , myErr );
  3283.       GOTO 9;
  3284.     END;
  3285.     
  3286.   IF toType <> typeChar THEN
  3287.     BEGIN
  3288.       gTempBool := CatchErr(   errAEWrongDataType , 13414 , myErr );
  3289.       GOTO 9;
  3290.     END;
  3291.     
  3292.   { convert the descriptor to typeAERecord }
  3293.   IF CatchErr(   AECoerceDesc(theAEDesc,typeAERecord,newDesc) , 13418 , myErr)
  3294.       THEN GOTO 9;
  3295.  
  3296. { get the text desc out of the record }
  3297.   gTempBool := CatchErr(   AEGetKeyDesc(newDesc,keyAEText,typeChar,result) , 13415 , myErr );
  3298.  
  3299. 9:    { finish up }
  3300.   gTempBool := CheckErr(   AEDisposeDesc(newDesc) , 13417 );
  3301.   CoerceStylTextToText := myErr;
  3302. END;    { CoerceStylTextToText }
  3303.  
  3304. {$S QuillNew}
  3305. FUNCTION CoerceStylTextToIntlText(theAEDesc: AEDesc; toType: DescType;
  3306.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;
  3307. { NOTE: I hard-code the script and language codes here.  I've also skipped
  3308.         the robustness checks.  Who needs 'em?!??
  3309. }
  3310. LABEL 9;
  3311. VAR myErr:            OSErr;
  3312.     stylTextRec:    AEDesc;
  3313.     textDesc:        AEDesc;
  3314. BEGIN
  3315.   myErr := errAECoercionFail;
  3316.   InitSomeDescs(@result,@stylTextRec,@textDesc,NIL,NIL);
  3317.   
  3318.   { convert the descriptor to typeAERecord }
  3319.   IF CatchErr(   AECoerceDesc(theAEDesc,typeAERecord,stylTextRec) , 23313 , myErr )
  3320.       THEN GOTO 9;
  3321.       
  3322.   { get the text out }
  3323.   IF CatchErr(   AEGetKeyDesc(stylTextRec,keyAEText,typeChar,textDesc) , 23314 , myErr )
  3324.       THEN GOTO 9;
  3325.       
  3326.   { make it into typeIntlText }
  3327.   gTempBool := CatchErr(   TextToIntlText(textDesc,smRoman,langEnglish,result) , 23315 , myErr );
  3328.       
  3329. 9:
  3330.  
  3331.   gTempBool := CheckErr(   DisposeSomeDescs(@stylTextRec,@textDesc,NIL,NIL,NIL) , 23316 );
  3332.   
  3333.   CoerceStylTextToIntlText := myErr;
  3334. END;    { CoerceStylTextToIntlText }
  3335.  
  3336. {$S QuillNew2}
  3337. FUNCTION CoerceIntlTextToText(theAEDesc: AEDesc; toType: DescType;
  3338.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;
  3339. { NOTE:    I throw away the script/language codes here.  I've also
  3340.         skipped any robustness checks.
  3341. }
  3342. BEGIN
  3343.   CoerceIntlTextToText := IntlTextToText(theAEDesc,result,gTempInt,gTempInt);
  3344. END;    { CoerceIntlTextToText }
  3345.  
  3346. {$S QuillNew2}
  3347. FUNCTION CoerceTextToIntlText(theAEDesc: AEDesc; toType: DescType;
  3348.     handlerRefCon: LongInt; VAR result: AEDesc): OSErr;
  3349. { NOTE:    I hard-code the script/language codes here.  I've also
  3350.         skipped any robustness checks.
  3351.         
  3352.         I'm not actually sure I NEED this routine anywhere.
  3353. }
  3354. BEGIN
  3355.   CoerceTextToIntlText := TextToIntlText(theAEDesc,smRoman,langEnglish,result);
  3356. END;    { CoerceTextToIntlText }
  3357.  
  3358.  
  3359. {$S QuillNew}
  3360. FUNCTION CompareTextDescs(text1: AEDesc; text2: AEDesc; VAR result: DescType): OSErr;
  3361. { this routine compares two pieces of text, given by descriptors of typeChar,
  3362.   and returns an ordering relation:  either kAEEquals, kAEGreaterThan, or
  3363.   kAELessThan
  3364.   INPUTS:    text1        descriptor for first piece of text
  3365.               text2        descriptor for second piece of text
  3366.             result        return VAR for comparison result, expressed as a DescType
  3367.   OUTPUTS:    error code (noErr if none)
  3368.   NOTES:    first we use EqualString to see if the texts are equal to at least
  3369.               255 characters, ignoring case but not diacriticals.  If they're equal
  3370.             by that test, we return kAEEqual.  Otherwise we turn to IUMagString
  3371.             (which looks at all the characters, but unfortunately is sensitive
  3372.             to case as well as diacriticals) to get the ordering.
  3373.             **CHECK - this is a mixed-bag string-ordering system, used for
  3374.             convenience; we may want to improve it later.
  3375. }
  3376. LABEL 9;
  3377. VAR myErr:        OSErr;    
  3378.     text1Str:    Str255;
  3379.     text2Str:    Str255;
  3380.     text1Ptr:    Ptr;
  3381.     text1Len:    LongInt;
  3382.     text2Ptr:    Ptr;
  3383.     text2Len:    LongInt;
  3384.     iuRes:        INTEGER;
  3385. BEGIN
  3386.   myErr := genericErr;
  3387.   
  3388.   { turn the text into strings }
  3389.   IF CatchErr(   TextDescToStr(text1,text1Str,gActSize) , 16013 ,myErr )
  3390.       THEN GOTO 9;
  3391.       
  3392.   IF CatchErr(   TextDescToStr(text2,text2Str,gActSize) , 16014 ,myErr )
  3393.       THEN GOTO 9;
  3394.       
  3395.   IF EqualString(text1Str,text2Str,FALSE,TRUE) THEN        { ignoring case but not diacriticals }
  3396.     BEGIN
  3397.       result := kAEEquals;
  3398.       GOTO 9;
  3399.     END;
  3400.     
  3401.   { they weren't equal with EqualString; use IUMagString to get ordering }
  3402.   
  3403.   WITH text1 DO
  3404.     BEGIN
  3405.       HLock(dataHandle);
  3406.       text1Ptr := dataHandle^;
  3407.       text1Len := GetHandleSize(dataHandle);
  3408.     END;
  3409.     
  3410.   WITH text2 DO
  3411.     BEGIN
  3412.       HLock(dataHandle);
  3413.       text2Ptr := dataHandle^;
  3414.       text2Len := GetHandleSize(dataHandle);
  3415.     END;
  3416.     
  3417.   iuRes := IUMagString(text1Ptr,text2Ptr,text1Len,text2Len);
  3418.   
  3419.   IF iuRes = -1 THEN result := kAELessThan
  3420.   ELSE IF iuRes = 0 THEN result := kAEEquals    { can this even happen, since the first 255 chars were not equal under EqualString? }
  3421.   ELSE result := kAEGreaterThan;
  3422.   
  3423.   HUnlock(text1.dataHandle);
  3424.   HUnlock(text2.dataHandle);
  3425.   
  3426.   myErr := noErr;
  3427.   
  3428. 9:    { finish up }
  3429.   
  3430.   CompareTextDescs := myErr;
  3431. END;    { CompareTextDescs }
  3432.  
  3433. { $S QuillNew2}
  3434. PROCEDURE ContinueKeyBuffering(key: CHAR; window: WindowPtr);
  3435. { this routine is called to add a character (normal or delete)
  3436.   to the key buffer when the buffer is "not empty" - or, more
  3437.   precisely, after one or more typed characters has been entered
  3438.   into the buffer.  Due to the special handling of Delete characters,
  3439.   there may be zero characters in the buffer at this time (if
  3440.   Delecte chars have cancelled out normal chars), but the buffer
  3441.   is not considered empty (because it has recorded some key events).
  3442.   See StartKeyBuffering for more detail.
  3443.   INPUTS:    key            the character that's been typed
  3444.               window        ptr to the window being typed into (only used
  3445.                         for robustness checking)
  3446.   OUTPUTS:    none
  3447.   NOTES:    we may want to do more sophisticated error handling
  3448. }
  3449. BEGIN
  3450.   WITH keyBuffer DO
  3451.     BEGIN
  3452.     
  3453.       IF bufEmpty THEN
  3454.         BEGIN
  3455.           DoMyAlert('Trouble - ContinueKeyBuffering called with empty buffer!');
  3456.           EXIT(ContinueKeyBuffering);
  3457.         END;
  3458.         
  3459.       IF window <> bufWndw THEN
  3460.         BEGIN
  3461.           DoMyAlert('Trouble - windows do not match in ContinueKeyBuffering!');
  3462.           EXIT(ContinueKeyBuffering);
  3463.         END;
  3464.         
  3465.       IF key = CHR(kDelChar) THEN
  3466.         BEGIN
  3467.           { Delete char - if there are normal chars in the buffer, drop one; otherwise }
  3468.           { increase the count of "uncancelled" Delete's                               }
  3469.           IF bufCharCount = 0 THEN bufDelCount := bufDelCount + 1 ELSE bufCharCount := bufCharCount - 1;
  3470.           EXIT(ContinueKeyBuffering);
  3471.         END;
  3472.         
  3473.       { if we get this far, it's a normal character }
  3474.       IF bufCharCount >= bufSize THEN
  3475.         BEGIN
  3476.           IF NOT GrowKeyBuffer THEN
  3477.             BEGIN
  3478.               DoMyAlert('Trouble in ContinueKeyBuffering - out of memory!');    { this is a true error and should be handled better }
  3479.               EXIT(ContinueKeyBuffering);
  3480.             END;
  3481.         END;
  3482.         
  3483.       { we have room - add the character }
  3484.       bufChars^^[bufCharCount] := key;
  3485.       bufCharCount := bufCharCount + 1;
  3486.     END;    { of WITH keyBuffer }
  3487.     
  3488. END;    { of ContinueKeyBuffering }
  3489.  
  3490.  
  3491.  
  3492. {$S QuillNew}
  3493. FUNCTION CountDelChars(textPtr: Ptr; textLength: LongInt;
  3494.     delChar: SignedByte): LongInt;
  3495. { count the occurrences of a particular character in a piece
  3496.   of text given by ptr and length.  We talk about the char as
  3497.   "delChar" because this routine is aminly used to count delimiter
  3498.   characters (CR for lines, comma for items), but any character
  3499.   can be used.
  3500.   INPUTS:    textPtr            ptr to the start of the text
  3501.               textLength        length of the text
  3502.             delChar            ascii value of the char to be counted
  3503.   OUTPUTS:    number of occurrences of the delChar in the text
  3504.   NOTES:    when using this routine to get the number of lines
  3505.               or items in some text, remember that the number of
  3506.             lines/items is ONE MORE than the number of CRs/commas
  3507.             (e.g., a string with no CRs still has one line)
  3508. }
  3509. VAR endPlus1Ptr:    Ptr;
  3510.     count:        LongInt;
  3511. BEGIN
  3512.   endPlus1Ptr := Ptr(ORD(textPtr) + textLength);    { ptr to 1 byte beyond the end of the text }
  3513.   count := 0;
  3514.   WHILE textPtr <> endPlus1Ptr DO
  3515.     BEGIN
  3516.       IF textPtr^ = delChar THEN count := count + 1;
  3517.       textPtr := Ptr(ORD(textPtr) + 1);
  3518.     END;
  3519.   CountDelChars := count;
  3520. END;    { CountDelChars }
  3521.  
  3522. {$S QuillNew}
  3523. FUNCTION CountTextElems(srcText: TextToken; elemClass: DescType;
  3524.     VAR elemCount: LongInt): OSErr;
  3525. { this routine counts the number of text elements of a given class - 
  3526.   chars, words, lines, or items - contained in a given piece of text
  3527.   specified by a text token.
  3528.   INPUTS:    srcText            the text
  3529.               elemClass        class of the text element to be counted
  3530.               elemCount        return VAR number of elements of that class
  3531.   OUTPUTS:    error code (noErr if none).  Currently the only possible
  3532.               error is errAEWrongDataType, indicating an illegal elemClass
  3533.   NOTES:    unfortunately, we can't do a CASE statement on elemClass
  3534.               with our current Pascal compiler
  3535.             7/1/91    BHM        Added "spots"
  3536. }
  3537. LABEL 9;
  3538. VAR myErr:        OSErr;
  3539.     textHndl:    Handle;
  3540.     textPtr:    Ptr;
  3541.     textLength:    LongInt;
  3542. BEGIN
  3543.   myErr := genericErr;
  3544.   elemCount := -1;    { illegal value, easily recognized }
  3545.   
  3546.   IF elemClass = cChar THEN
  3547.     BEGIN
  3548.       elemCount := srcText.tokenLength;    { this is easy . . . . }
  3549.       myErr := noErr;
  3550.       GOTO 9;    { finish up }
  3551.     END;
  3552.     
  3553.   IF elemClass = cSpot THEN
  3554.     BEGIN
  3555.       elemCount := srcText.tokenLength + 1;
  3556.       myErr := noErr;
  3557.       GOTO 9;
  3558.     END;
  3559.     
  3560.   WITH srcText DO
  3561.     BEGIN
  3562.       textHndl := DocumentPeek(tokenWndw)^.docTE^^.hText;
  3563.       HLock(textHndl);
  3564.       textPtr := Ptr(ORD(textHndl^) + tokenOffset);
  3565.       textLength := tokenLength;
  3566.     END;
  3567.     
  3568.   myErr := noErr;    { rare to put this in the middle, but it makes sense here }
  3569.         
  3570.   IF elemClass = cWord THEN elemCount := CountWords(textPtr,textLength)
  3571.   ELSE IF elemClass = cLine THEN elemCount := CountDelChars(textPtr,textLength,asciiCR) + 1
  3572.   ELSE IF elemClass = cItem THEN elemCount := CountDelChars(textPtr,textLength,asciiComma) + 1
  3573.   ELSE myErr := errAEWrongDataType;    { illegal element class }
  3574.   
  3575.   HUnlock(textHndl);
  3576.   
  3577. 9:    { finish up }
  3578.  
  3579.   CountTextElems := myErr;
  3580. END;    { CountTextElems }
  3581.  
  3582.  
  3583. {$S QuillNew}
  3584. FUNCTION CountWindows: INTEGER;
  3585. { count the number of currently open windows
  3586.   INPUTS:    none
  3587.   OUTPUTS:    the number of windows
  3588.   ERRORS:
  3589.   SIDE EFFECTS:
  3590. }
  3591. VAR i:        INTEGER;
  3592.     window:    WindowPtr;
  3593. BEGIN
  3594.   i := 0;
  3595.   window := FrontWindow;
  3596.   WHILE window <> NIL DO
  3597.     BEGIN
  3598.       i := i+1; 
  3599.       window := WindowPtr(WindowPeek(window)^.nextWindow);
  3600.     END;
  3601.   CountWindows := i;
  3602. END;    { CountWindows }
  3603.  
  3604. {$S QuillNew}
  3605. FUNCTION CountWords(textPtr: Ptr; textLength: LongInt): LongInt;
  3606. { count the number of words in a piece of text.
  3607.  
  3608.   A word is any stretch of contiguous bytes that contains no break characters,
  3609.   is of positive length, and is bounded by break characters and/or the start
  3610.   of the text and/or the end of the text.  Even text with no break characters
  3611.   can contain a word (the text "alpha" has 1 word).  However, some text contains 
  3612.   no words at all, e.g. a run of 17 spaces.  Text with 0 length contains no words.
  3613.   By definition a word cannot be of length 0.
  3614.   
  3615.   Break characters are defined by the routines ScanToBreak and ScanToNonBreak.
  3616.   As currently implemented, they think spaces and carriage returns are breaks,
  3617.   and nothing else.
  3618.   
  3619.   INPUTS:    textPtr            ptr to the text
  3620.               textLength        length of the text
  3621.   OUTPUTS:    number of words in the text
  3622. }
  3623. LABEL 9;
  3624. VAR count:            LongInt;
  3625.     endPtr:            Ptr;
  3626.     endPlus1Ptr:    Ptr;
  3627.     wordPtr:        Ptr;
  3628.     breakPtr:        Ptr;
  3629. BEGIN
  3630.   count := 0;
  3631.   
  3632.   IF textLength = 0 THEN GOTO 9;    { finish up }
  3633.   
  3634.   endPtr := Ptr(ORD(textPtr) + textLength - 1);    { ptr to last char of the text }
  3635.   endPlus1Ptr := Ptr(ORD(endPtr) + 1);            { useful to have around }
  3636.   
  3637.   { go to start of first word }
  3638.   ScanToNonBreak(textPtr,endPtr,wordPtr);
  3639.   
  3640.   IF wordPtr = endPlus1Ptr THEN GOTO 9;    { there wasn't any first word }
  3641.   
  3642.   count := 1;
  3643.   
  3644.   WHILE TRUE DO    { loop forever, sort of }
  3645.     BEGIN
  3646.       ScanToBreak(wordPtr,endPtr,breakPtr);
  3647.       IF breakPtr = endPlus1Ptr THEN GOTO 9;    { no more break chars, so no more words }
  3648.       
  3649.       { go to start of next word }
  3650.       ScanToNonBreak(breakPtr,endPtr,wordPtr);
  3651.       IF wordPtr = endPlus1Ptr THEN GOTO 9;    { there wasn't a next word }
  3652.       
  3653.       { sure there is }
  3654.       count := count + 1;
  3655.     END;
  3656.     
  3657. 9:    { finish up }
  3658.   CountWords := count;
  3659. END;    { CountWords }
  3660.  
  3661. {$S QuillNew2}
  3662. FUNCTION DecodeInsertionLoc(insertionLoc: AEDesc; VAR relObjToken: AEDesc; 
  3663.     VAR position: DescType): OSErr;
  3664. { this routine takes a descriptor of typeInsertionLoc and breaks it
  3665.   up into its constituent parts, the object (which can either be an
  3666.   object to put something before, after, or into (replace), OR a container
  3667.   to put something at the beginning or end of) and the position (which
  3668.   specifies either before, after, or replace, OR beginning of or end of).
  3669.   The object is resolved to a token (possibly the null descriptor, for
  3670.   the app's "default container").
  3671.   
  3672.   INPUTS:    insertionLoc    a descriptor of typeInsertionLoc
  3673.               relObjToken        return VAR for token representing the object
  3674.                             field of the insertion loc
  3675.             position        return VAR for enumerated value specifying
  3676.                             the position relative to the object (before/after/
  3677.                             replace, or beginning/end)
  3678.   OUTPUTS:    error code (noErr if none)
  3679.   NOTES:    (1) the object field must resolve to a single item, not a list
  3680. }
  3681. LABEL 9;
  3682. VAR myErr:        OSErr;
  3683.     newRec:        AEDesc;
  3684.     objDesc:    AEDesc;
  3685. BEGIN
  3686.   myErr := genericErr;
  3687.   InitSomeDescs(@relObjToken,@objDesc,@newRec,NIL,NIL);
  3688.   position := kAEBefore;
  3689.   
  3690.   { coerce insertion loc to AERecord }
  3691.   IF CatchErr(   AECoerceDesc(insertionLoc,typeAERecord,newRec) , 20421 , myErr )
  3692.       THEN GOTO 9;
  3693.   
  3694.   { get position }
  3695.   IF CatchErr(   AEGetKeyPtr(newRec,keyAEPosition,typeEnumerated,gReturnedType,@position,
  3696.       SizeOf(position),gActSize) , 20413 , myErr ) THEN GOTO 9;
  3697.       
  3698.   { validate it }
  3699.   IF (position <> kAEBefore) & (position <> kAEAfter) & (position <> kAEReplace) & 
  3700.       (position <> kAEBeginning) & (position <> kAEEnd) THEN
  3701.     BEGIN
  3702.       gTempBool := CatchErr(   errAEBadData , 20414 , myErr );
  3703.       GOTO 9;
  3704.     END;
  3705.     
  3706.   { get object }
  3707.   IF CatchErr(   AEGetKeyDesc(newRec,keyAEObject,typeWildCard,objDesc) , 20415 , 
  3708.       myErr ) THEN GOTO 9;
  3709.       
  3710.   { check for null }
  3711.   IF objDesc.descriptorType = typeNull THEN relObjToken := gNullDesc
  3712.   ELSE
  3713.     BEGIN
  3714.       { better be an object spec }
  3715.       IF objDesc.descriptorType <> typeObjectSpecifier THEN
  3716.         BEGIN
  3717.           gTempBool := CatchErr(   errAEWrongDataType , 20416 , myErr );
  3718.           GOTO 9;
  3719.         END;
  3720.         
  3721.       { we've got an obj spec - let's resolve it }
  3722.       IF CatchErr(   AEResolve(objDesc,kAEIDoMinimum,relObjToken) , 20417 , myErr ) THEN GOTO 9;
  3723.       
  3724.       { it better not be a list }
  3725.       IF relObjToken.descriptorType = typeAEList THEN
  3726.         BEGIN
  3727.           gTempBool := CatchErr(   errAENeedSingleItem , 20418 , myErr );
  3728.           GOTO 9;
  3729.         END;
  3730.       
  3731.     END;    { of object not null }
  3732.     
  3733. 9:
  3734.   IF myErr <> noErr THEN
  3735.     BEGIN
  3736.       { you only want to dispose of relObjToken in the error case }
  3737.       gTempBool := CheckErr(   AEDisposeDesc(relObjToken) , 20419 );
  3738.       position := kAEBefore; { just for neatness }
  3739.     END;
  3740.     
  3741.   gTempBool := CheckErr(   DisposeSomeDescs(@objDesc,@newRec,NIL,NIL,NIL) , 20420 );
  3742.     
  3743.   DecodeInsertionLoc := myErr;
  3744. END;    { DecodeInsertionLoc }
  3745.  
  3746. {$S QuillNew2}
  3747. FUNCTION DecodeOrdinal(ordData: AEDesc; count: LongInt; VAR index: LongInt; 
  3748.     VAR allFlag: BOOLEAN; VAR zeroFlag: BOOLEAN): OSErr;
  3749. { this routine is used whenever an element is specified by an absolute position
  3750.   within a sequence of elements - such as "word 3 of window 'johnson'", "any line
  3751.   of item 17 of window 'Kelvin'", etc.  The data specifying the position can be
  3752.   a positive integer (which just means the actual position of the element in the
  3753.   sequence: 1 for the first element, 2 for the second, etc.), a negative integer
  3754.   (which indicates position relative to the last element of the sequence: -1 is
  3755.   the last element, -2 the next to last, etc.), or a descriptor of typeAbsoluteOrdinal:
  3756.   kAEFirst, kAELast, kAEMiddle, kAEAny, or kAEAll.  
  3757.   
  3758.   DecodeOrdinal takes the data specifying the position, and a count of all the elements
  3759.   in the sequence under consideration, and returns (whenever possible) a positive integer
  3760.   (in the return VAR index) representing the actual position of the element in the sequence 
  3761.   (1 for first, 2 for second, etc.).  It also returns flags indicating (a) whether the 
  3762.   ordinal was kAEAll and (b) whether the count was 0; both of these are conditions that 
  3763.   many calling routines will have to special-case.  In the case of kAEAll, the return VAR 
  3764.   index is set to the count; in the case of count = 0, the return VAR index is set to 0.
  3765.   
  3766.   There are a few error conditions:  (a) count < 0; (b) bad ordData (not an integer, and
  3767.   not one of the five defined absolute ordinal specifiers).  **CHECK - should "integer ordData
  3768.   out of range" (for example, an integer > count, or < -count, or = 0) be an error,
  3769.   or should we allow that so that people can talk about "the hypothetical element
  3770.   beyond the last", or whatever?  For now, let's make that a non-error.
  3771.   
  3772.   INPUTS:    ordData        a descriptor that specifies an ordinal - either
  3773.                           an integer (positive or negative) or something
  3774.                         of typeAbsoluteOrdinal
  3775.             count        the total number of elements in the group involved
  3776.                         (number of windows, number or chars, or whatever)
  3777.             index        return VAR for the actual position being described
  3778.             allFlag        return VAR: TRUE if the ordData was kAEAll, FALSE o.w.
  3779.             zeroFlag    return VAR: TRUE if the count was zero (for many
  3780.                         calling routines this is an error condition), FALSE o.w.
  3781.   OUTPUTS:    error code (noErr if none)
  3782. }
  3783. LABEL 9;
  3784. VAR myErr:    OSErr;
  3785.     absOrd:    DescType;
  3786.     intOrd:    LongInt;
  3787. BEGIN
  3788.   myErr := genericErr;
  3789.   index := count;
  3790.   allFlag := FALSE;
  3791.   
  3792.   zeroFlag := (count = 0);
  3793.   IF count < 0 THEN
  3794.     BEGIN
  3795.       myErr := errAEBadData;
  3796.       GOTO 9;
  3797.     END;
  3798.   
  3799.   myErr := MyAECoerceDescPtr(ordData,typeAbsoluteOrdinal,@absOrd,SizeOf(absOrd),gActSize);
  3800.   IF myErr = noErr THEN
  3801.     BEGIN
  3802.       { got an absolute ordinal }
  3803.       { note that, as we enter here, index = count and myErr = noErr }
  3804.       allFlag := (absOrd = kAEAll);
  3805.       IF allFlag THEN GOTO 9;    { finish up }
  3806.         
  3807.       IF (absOrd <> kAEFirst) & (absOrd <> kAELast) & (absOrd <> kAEMiddle) & (absOrd <> kAEAny) THEN
  3808.         BEGIN
  3809.           myErr := errAEBadData;
  3810.           GOTO 9;
  3811.         END;
  3812.         
  3813.       IF zeroFlag | (absOrd = kAELast) THEN GOTO 9; { in both cases, index = count (already done) }
  3814.         
  3815.       IF absOrd = kAEFirst THEN index := 1
  3816.       ELSE IF absOrd = kAEMiddle THEN index := (count + 1) DIV 2
  3817.       ELSE index := MyRandom(count);
  3818.       
  3819.       GOTO 9;
  3820.     END;    { of absolute ordinal }
  3821.     
  3822.   { try actual integer }
  3823.   IF CatchErr(   MyAECoerceDescPtr(ordData,typeLongInteger,@intOrd,SizeOf(intOrd),gActSize) ,
  3824.       19813 , myErr ) THEN GOTO 9;
  3825.       
  3826.   IF intOrd < 0 THEN index := count + intOrd + 1    { e.g., intOrd = -1 means index = count }
  3827.   ELSE index := intOrd;
  3828.   
  3829.   { should we validate index here (wrt count)?  let's skip it for now }
  3830.   
  3831. 9:    { finish up }
  3832.   DecodeOrdinal := myErr;
  3833. END;    { DecodeOrdinal }
  3834.  
  3835. {$S QuillNew2}
  3836. PROCEDURE DeleteThisText(myText: TextToken);
  3837. { delete the text represented by myText.  In the case
  3838.   of lines or items, we delete a delimiter (CR or comma,
  3839.   respectively) along with it - otherwise we would still
  3840.   have a (0-length) line or item.
  3841.   INPUTS:    myText        token for the text to be deleted
  3842.   OUTPUTS:    none
  3843.   NOTES:    for words, HyperCard will swallow an adjacent space
  3844.               (just one), but not adjacent CRs - should we do it
  3845.             that way?
  3846. }
  3847. BEGIN
  3848.   { note that myText is not VAR; we're dealing with a local copy }
  3849.   WITH myText DO
  3850.     BEGIN
  3851.       IF tokenClass = cSpot THEN EXIT(DeleteThisText);    { nothing to do }
  3852.       
  3853.       IF (tokenClass = cItem) | (tokenClass = cLine) THEN ExtendTextElem(myText);
  3854.       
  3855.       IF tokenClass = cWord THEN ExtendWord(myText);
  3856.           
  3857.       { ready to delete now }
  3858.       SelectTextToken(myText);
  3859.       TEDelete(DocumentPeek(tokenWndw)^.docTE);
  3860.       DirtyWindow(tokenWndw);
  3861.     END;
  3862.     
  3863. END;    { DeleteThisText }
  3864.  
  3865. {$S QuillNew2}
  3866. FUNCTION DeleteThisObj(myObj: AEDesc): OSErr;
  3867. { coerce the given obj into something that can be deleted - 
  3868.   a window, piece of text, or list thereof - and delete it.
  3869.   Since the list may contain embedded lists, the routine is
  3870.   potentially recursive.
  3871.   INPUTS:    myObj        the obj to be deleted
  3872.   OUTPUTS:    error code (noErr if none)
  3873.   NOTES:    if myObj is a list, we assume it's been given to us from
  3874.               the OSL, and is properly ordered so that, if we delete
  3875.             from the end of the list on up, we get no side effects
  3876. }
  3877. LABEL 9;
  3878. VAR myErr:        OSErr;
  3879.     tempDesc:    AEDesc;
  3880.     delObj:        AEDesc;
  3881.     itemCount:    LongInt;
  3882.     i:            LongInt;
  3883.     thisItem:    AEDesc;
  3884.     window:        WindowPtr;
  3885.     myText:        TextToken;
  3886. BEGIN
  3887.   myErr := genericErr;
  3888.   tempDesc := gNullDesc;
  3889.   
  3890.       { if it's an obj spec, we resolve it - because we don't want to coerce it to a list }
  3891.       { **CHECK - note clever new use of assignments - it's subtle, be careful! - BHM 9/3/91 }
  3892.       { it avoids an unnecessary duplication }
  3893.       
  3894.       { delObj gets neither initialized nor disposed of; it's only another name for some }
  3895.       { other descriptor (either myObj or tempObj, depending)                            }
  3896.       
  3897.   delObj := myObj;
  3898.   IF delObj.descriptorType = typeObjectSpecifier THEN
  3899.     BEGIN
  3900.       IF CatchErr(   AEResolve(myObj,kAEIDoMinimum,tempDesc) , 21613 , myErr )
  3901.           THEN GOTO 9;
  3902.       delObj := tempDesc;
  3903.     END;
  3904.   
  3905.   
  3906.   IF delObj.descriptorType = typeAEList THEN
  3907.     BEGIN
  3908.       { count the items }
  3909.       IF CatchErr(   AECountItems(delObj,itemCount) , 21614 , myErr ) THEN GOTO 9;
  3910.       
  3911.       { work backwards through the list, calling yourself recursively }
  3912.       FOR i := itemCount DOWNTO 1 DO
  3913.         BEGIN
  3914.           { get the item }
  3915.           IF CatchErr(   AEGetNthDesc(delObj,i,typeWildCard,gReturnedKeywd,thisItem) , 21615 , 
  3916.               myErr ) THEN GOTO 9;
  3917.               
  3918.           { delete it }
  3919.           IF CatchErr(   DeleteThisObj(thisItem) , 21616 , myErr ) THEN GOTO 9;
  3920.           
  3921.           { dispose of the item }
  3922.           gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 21617 );
  3923.           thisItem := gNullDesc;    { just for neatness }
  3924.         END;    { of FOR loop }
  3925.       GOTO 9;
  3926.     END;    { of list }
  3927.     
  3928.   { not a list - get something we can delete }
  3929.   IF MyAECoerceDescPtr(delObj,typeMyWndw,@window,SizeOf(window),gActSize) = noErr THEN
  3930.     BEGIN
  3931.       { it's a window }
  3932.       ShutTheWindow(window);
  3933.       myErr := noErr;
  3934.       GOTO 9;
  3935.     END;
  3936.     
  3937.   IF MyAECoerceDescPtr(delObj,typeMyText,@myText,SizeOf(myText),gActSize) = noErr THEN
  3938.     BEGIN
  3939.       { it's text }
  3940.       DeleteThisText(myText);
  3941.       myErr := noErr;
  3942.       GOTO 9;
  3943.     END;
  3944.     
  3945.   { it's nothing we can delete }
  3946.   myErr := errAEEventNotHandled;    { or whatever }
  3947.   
  3948. 9:    { finish up }
  3949.  
  3950.   gTempBool := CheckErr(   AEDisposeDesc(tempDesc) , 21618 );    { but NOT delObj! }
  3951.  
  3952.   DeleteThisObj := myErr;
  3953. END;    { DeleteThisObj }
  3954.  
  3955.  
  3956. {$S QuillNew2}
  3957. PROCEDURE DestroyKeyBuffer;
  3958. { this routine throws away the storage associated
  3959.   with the key buffer
  3960.   INPUTS:    none
  3961.   OUTPUTS:    none
  3962.   10/03/91    BHM        Added bufDesc
  3963. }
  3964. BEGIN
  3965.   DisposHandle(Handle(keyBuffer.bufChars));
  3966.   gTempBool := CheckErr(   AEDisposeDesc(keyBuffer.bufDesc) , 22113 );
  3967. END;    { DestroyKeyBuffer }
  3968.  
  3969.  
  3970. {$S QuillNew }
  3971. PROCEDURE DirtyWindow(window: WindowPtr);
  3972. { mark the given window as dirty 
  3973.   INPUTS:    window        ptr to the window
  3974.   OUTPUTS:    none
  3975. }
  3976. BEGIN
  3977.   DocumentPeek(window)^.dirtyFlag := TRUE;
  3978. END;    { DirtyWindow }
  3979.  
  3980. {$S QuillNew }
  3981. FUNCTION DisposeSomeDescs(desc1Ptr, desc2Ptr, desc3Ptr, desc4Ptr, desc5Ptr: DescPtr):  OSErr;
  3982. { dispose of a bunch of descriptors.  The inputs are pointers to the descriptors.  
  3983.   If one or more of the pointers is NIL, then the routine ignores all the inputs 
  3984.   after that one (they should be NIL, too).  So, for example, if desc3Ptr is NIL, 
  3985.   only the descriptors pointed to by desc1Ptr and desc2Ptr are disposed of.
  3986.   INPUTS:    as above
  3987.   OUTPUTS:    error code (noErr if none).  If any of the AEDisposeDesc calls returns
  3988.               an error, DisposeSomeDesc will return the first such error generated;
  3989.             but it will continue to (try to) dispose of all the input descriptors.
  3990.   NOTES:    (1)    as currently spec'ed, AEDisposeDesc never returns an error (just
  3991.                   noErr); and for valid descriptors, it's hard to imagine what kind
  3992.                 of error it would return.  So all the error details here may be
  3993.                 utterly pointless.  Better safe than sorry, I always say.
  3994.             (2)    **WARNING** if any of the inputs is NIL, it and all the subsequent
  3995.                 inputs are ignored
  3996.             (3)    **ANOTHER WARNING** this routine can be used to dispose of both
  3997.                 local AEDesc's (local to the caller) and/or AEDesc's the caller
  3998.                 is creating & returning for some higher routine to use (such desc's
  3999.                 generally show up as VAR inputs in the calling routine).  You ONLY 
  4000.                 dispose of these VAR input desc's to clean up when your routine 
  4001.                 generates an error.  Thus many routines that call DisposeSomeDescs 
  4002.                 will contain two calls to it, one to be used when the call succeeds 
  4003.                 (to get rid of any local desc's that may have been created) and one 
  4004.                 to be used when the call fails (to get rid of both local and return 
  4005.                 desc's that may have been created).  If you intialize all desc's to 
  4006.                 the null desc at the start of your routine (using InitSomeDescs), 
  4007.                 you won't have to keep track of which ones you have already created 
  4008.                 when you hit an error.  But you do have to distinguish between local 
  4009.                 desc's and return desc's.
  4010.                 See routines that call InitSomeDescs and DisposeSomeDescs to see what 
  4011.                 I mean.
  4012.                 
  4013. }
  4014. LABEL 9;
  4015. VAR myErr:        OSErr;
  4016.     tempErr:    OSErr;
  4017. BEGIN
  4018.   myErr := noErr;
  4019.   IF desc1Ptr = NIL THEN GOTO 9;    { finish up }
  4020.   myErr := AEDisposeDesc(desc1Ptr^);
  4021.   
  4022.   IF desc2Ptr = NIL THEN GOTO 9;
  4023.   tempErr := AEDisposeDesc(desc2Ptr^);
  4024.   IF myErr = noErr THEN myErr := tempErr;    { we want to keep the first real error }
  4025.   
  4026.   IF desc3Ptr = NIL THEN GOTO 9;
  4027.   tempErr := AEDisposeDesc(desc3Ptr^);
  4028.   IF myErr = noErr THEN myErr := tempErr;
  4029.                       
  4030.   IF desc4Ptr = NIL THEN GOTO 9;
  4031.   tempErr := AEDisposeDesc(desc4Ptr^);
  4032.   IF myErr = noErr THEN myErr := tempErr;
  4033.   
  4034.   IF desc5Ptr = NIL THEN GOTO 9;
  4035.   tempErr := AEDisposeDesc(desc5Ptr^);
  4036.   IF myErr = noErr THEN myErr := tempErr;
  4037.   
  4038. 9:    { finish up }
  4039.   DisposeSomeDescs := myErr;
  4040. END;    { DisposeSomeDescs }
  4041.  
  4042. {$S QuillNew }
  4043. PROCEDURE DoDragWindow(theWindow: WindowPtr; startPt: Point; boundsRect: Rect);
  4044. { this routine does the normal DragWindow, and then sends an AppleEvent to
  4045.   (re)set the window position to its new value, for recording purposes 
  4046.   INPUTS:    same as DragWindow
  4047.   OUTPUTS:    none
  4048.   ERRORS:
  4049.   SIDE EFFECTS:
  4050. }
  4051. VAR newPos:    Point;
  4052.     index:    INTEGER;
  4053. BEGIN
  4054.   DragWindow(theWindow,startPt,boundsRect);
  4055.   newPos := WindowPeek(theWindow)^.strucRgn^^.rgnBBox.topLeft;    { we use the structure rect for that }
  4056.   index := IndexFromWndwPtr(theWindow);
  4057.   SendAESetWndwPos(index,newPos);
  4058. END;    { DoDragWindow }
  4059.  
  4060. {$S QuillNew}
  4061. PROCEDURE DoHighLevelEvent(event: EventRecord);
  4062. BEGIN
  4063.  { gTempBool := CheckErr(   AEProcessAppleEvent(event) , 1213 );}
  4064.  gTempLong := AEProcessAppleEvent(event);
  4065. END;    { DoHighLevelEvent }
  4066.  
  4067. PROCEDURE DoItemErr(itemNum: INTEGER; theErr: OSErr; placeNum: INTEGER); 
  4068. { this is a routine to call when you get an error while dealing with 
  4069.   some item in an AEList - an error you want to register, but not enough
  4070.   to make you want to abort whatever activity you're involved in (for 
  4071.   example:  in HandlePrintDocs, if one of the items in the direct-object
  4072.   list turns out to be something you can't print).  As implemented here,
  4073.   it puts up a dialog giving the item number, the error number, and
  4074.   the place number (a unique number associated with the place in the
  4075.   code where the error was generated).  In a real application, the actions
  4076.   you would take would depend on where the error occurred, what kind
  4077.   of error it was, etc.
  4078.   INPUTS:    itemNum        number of the item that occasioned the error
  4079.               theErr        error code
  4080.             placeNum    location of the error
  4081.   OUTPUTS:    none
  4082.   NOTES:
  4083. }
  4084. VAR itemStr:    Str255;
  4085. BEGIN
  4086.   IF (NOT gShowAllErrs) & gInHandler THEN EXIT(DoItemErr);    { **CHECK - experimental }
  4087.   itemStr := Concat('trouble with item# ',MyNumToStr(itemNum),
  4088.       ':  err# ',MyNumToStr(theErr),' at ',MyNumToStr(placeNum));
  4089.   DoMyAlert(itemStr);
  4090. END;
  4091.  
  4092. {$S QuillNew }
  4093. PROCEDURE DoMenuClose(window: WindowPtr);
  4094. { close the given window.  We check with the user on
  4095.   save/don't save options, then bundle up the Close as
  4096.   an AppleEvent and send it to ourself.
  4097.   INPUTS:    window        the window to be closed
  4098.   OUTPUTS:    none
  4099.   ERRORS:
  4100.   SIDE EFFECTS:
  4101. }
  4102. VAR wndwTitle:        Str255;
  4103.     saveFlag:        BOOLEAN;
  4104.     docFileGood:    BOOLEAN;
  4105.     fileParamFlag:    BOOLEAN;
  4106.     fileSpec:        FSSpec;
  4107. BEGIN
  4108.   { first the DA window stuff - **CHECK on whether we really need this }
  4109.   IF IsDAWindow(window) THEN
  4110.     BEGIN
  4111.       CloseDeskAcc(WindowPeek( window )^.windowKind);
  4112.       EXIT(DoMenuClose);
  4113.     END;
  4114.     
  4115.   IF IsAppWindow(window) THEN
  4116.     BEGIN
  4117.     
  4118.       { if window dirty, then ask user about saving and, if necessary, to what file }
  4119.       IF WindowIsDirty(window) THEN
  4120.         BEGIN
  4121.           IF NOT AskBeforeClosing(window,saveFlag,docFileGood,fileSpec) THEN EXIT(DoMenuClose);    { user cancelled out of AskBeforeClosing }
  4122.         END
  4123.       ELSE
  4124.         BEGIN
  4125.           saveFlag := FALSE;
  4126.           docFileGood := FALSE;    { just for neatness }
  4127.         END;
  4128.         
  4129.       { time to send the Close event }
  4130.       { if we're not going to save, don't send the
  4131.         optional file parameter.  Also, if we are
  4132.         going to save, but the file spec came from
  4133.         the window doc record (as opposed to user
  4134.         actions), then, for recording purposes, we
  4135.         STILL don't want to send along the file
  4136.         parameter }
  4137.       fileParamFlag := saveFlag & (NOT docFileGood);
  4138.         
  4139.       SendAEClose(window,saveFlag,fileParamFlag,fileSpec);
  4140.     END;    { of app window case }
  4141.     
  4142.   { if we get to here, we're fine }
  4143. END;    { DoMenuClose }
  4144.  
  4145. {$S QuillNew}
  4146. PROCEDURE DoMenuEdit(window: WindowPtr; editCode: INTEGER);
  4147. { used when Copy, Cut, or Paste is chosen from the edit
  4148.   menu.  Concoct an object representing selection in the given
  4149.   window, and send an Apple Event to perform the given edit 
  4150.   action on that object.
  4151.   INPUTS:    window        ptr to the window
  4152.               editCode    defined constant for the edit action:
  4153.                         iCopy, iCut, or iPaste
  4154.   OUTPUTS:    none
  4155.   NOTES:    (1) an easier way to do the menu command would be to
  4156.               send the event without parameters, which would then
  4157.             act on the current selection; but this records better
  4158.             (2) IMPORTANT:  this routine is NOT used with Clear
  4159.             (which is not a Core AppleEvent; we use Set Data)
  4160.             or Select All (which may not even be an AppleEvent
  4161.             action; we'll see . . . .)
  4162. }
  4163. LABEL 9;
  4164. VAR selText:        AEDesc;
  4165.     eventID:        DescType;
  4166.     myAppleEvent:    AppleEvent;
  4167.     defReply:        AppleEvent;
  4168. BEGIN
  4169.   InitSomeDescs(@selText,@myAppleEvent,@defReply,NIL,NIL);
  4170.   
  4171.   { make an object representing the selected text }
  4172.   IF CheckErr(   MakeSelTextObj(window,selText) , 17513 ) THEN GOTO 9;
  4173.   
  4174.   { get the event ID }
  4175.   CASE editCode OF
  4176.     iCopy:    eventID := kAECopy;
  4177.     iCut:    eventID := kAECut;
  4178.     iPaste:    eventID := kAEPaste;
  4179.   END;
  4180.   
  4181.   { create event }
  4182.   IF CheckErr(    AECreateAppleEvent(kAEMiscStandards,eventID,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,myAppleEvent) , 17514 )
  4183.       THEN GOTO 9;
  4184.       
  4185.   { add parameter }
  4186.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyDirectObject,selText) , 17515 ) THEN GOTO 9;
  4187.   
  4188.   { send the event }
  4189.   gTempBool := CheckErr(   AESend(myAppleEvent,defReply,kAENoReply+kAECanInteract,kAENormalPriority,kAEDefaultTimeOut,NIL,NIL) ,
  4190.       17516 );
  4191.       
  4192. 9:    { finish up }
  4193.   gTempBool := CheckErr(   DisposeSomeDescs(@selText,@myAppleEvent,@defReply,NIL,NIL) , 17517 );
  4194. END;    { DoMenuEdit }
  4195.  
  4196. {$S QuillNew}
  4197. PROCEDURE DoMenuMathoms(menuItem: INTEGER);
  4198. { implements the Mathoms menu, which for now just
  4199.   has the toggle-the-error-mode command
  4200.   INPUTS:    menuItem        item number from Mathoms menu
  4201.   OUTPUTS:    none
  4202. }
  4203. LABEL 9;
  4204. VAR newErrMode:        DescType;
  4205.     propDataDesc:    AEDesc;
  4206. BEGIN
  4207.   propDataDesc := gNullDesc;
  4208.   IF menuItem = iShowAllErrs THEN
  4209.     BEGIN
  4210.       { send an AppleEvent to change the app's error mode }
  4211.       
  4212.       { create the data desc }
  4213.       IF gShowAllErrs THEN newErrMode := kShowFewErrs
  4214.       ELSE newErrMode := kShowAllErrs;
  4215.       
  4216.       IF CheckErr(   AECreateDesc(typeEnumerated,@newErrMode,SizeOf(newErrMode),propDataDesc) , 
  4217.           18514 ) THEN GOTO 9;
  4218.           
  4219.       { now send }
  4220.       SendAESetObjProp(gNullDesc,pErrMode,propDataDesc);
  4221.     END;
  4222.       
  4223. 9:    { finish up }
  4224.   gTempBool := CheckErr(   AEDisposeDesc(propDataDesc) , 18516 );
  4225. END;    { DoMenuMathoms }
  4226.  
  4227. {$S QuillNew}
  4228. PROCEDURE DoMenuNew;
  4229. { send a CreateElement event to make a new, frontmost window
  4230.   INPUTS:    none
  4231.   OUTPUTS:    none
  4232.   ERRORS:
  4233.   SIDE EFFECTS:
  4234. }
  4235. LABEL 9;
  4236. VAR myAppleEvent:    AEDesc;
  4237.     insertionLoc:    AEDesc;
  4238.     newClass:        DescType;
  4239.     defReply:        AEDesc;
  4240. BEGIN
  4241.   InitSomeDescs(@myAppleEvent,@insertionLoc,@defReply,NIL,NIL);
  4242.   
  4243.   { create the event }
  4244.   IF CheckErr(   AECreateAppleEvent(kAECoreSuite,kAECreateElement,gSelfAddrDesc,kAutoGenerateReturnID,
  4245.       kAnyTransactionID,myAppleEvent) , 22813 ) THEN GOTO 9;
  4246.       
  4247.   { create insertion loc - "beginning of null container" }
  4248.   IF CheckErr(   MakeInsertionLoc(gNullDesc,kAEBeginning,insertionLoc) , 22814 )
  4249.       THEN GOTO 9;
  4250.   
  4251.   { add insertion loc to event }
  4252.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyAEInsertHere,insertionLoc) , 22815 )
  4253.       THEN GOTO 9;
  4254.       
  4255.   { add desired class }
  4256.   newClass := cDocument;
  4257.   IF CheckErr(   AEPutParamPtr(myAppleEvent,keyAEObjectClass,typeType,@newClass,SizeOf(newClass)) , 
  4258.       22816 ) THEN GOTO 9;
  4259.       
  4260.   { send the event }
  4261.   gTempBool := CheckErr(   AESend(myAppleEvent,defReply,kAENoReply+kAECanInteract,kAENormalPriority,
  4262.       kAEDefaultTimeOut,NIL,NIL) , 22817 );
  4263.       
  4264. 9:
  4265.   { not really necessary to dispose of the default reply - we didn't ask for one - }
  4266.   { but I'm neat                                                                   }
  4267.   gTempBool := CheckErr(   DisposeSomeDescs(@myAppleEvent,@insertionLoc,@defReply,NIL,NIL) , 22819 );
  4268. END;    { DoMenuNew }
  4269.  
  4270. {$S QuillNew}
  4271. PROCEDURE DoMenuOpen;
  4272. { get a file from the user and open a new window for it (by sending yourself the 
  4273.   AppleEvent)
  4274. INPUTS:        none
  4275. OUTPUTS:    none
  4276. ERRORS:
  4277. SIDE EFFECTS:
  4278. }
  4279. VAR myTypeList:    SFTypeList;
  4280.     mySFReply:    StandardFileReply;
  4281. BEGIN
  4282.   myTypeList[0] := 'QUIL';
  4283.   StandardGetFile(NIL,1,myTypeList,mySFReply);
  4284.   IF NOT mySFReply.sfGood THEN EXIT(DoMenuOpen);    { user cancelled }
  4285.   SendAEOpenDoc(mySFReply.sfFile);
  4286. END;    { DoMenuOpen }
  4287.  
  4288. {$S QuillNew}
  4289. PROCEDURE DoMenuPrint;
  4290. { called when the user selects Print from the File menu.  Package
  4291.   up the front window as an object, and ship it off to myself
  4292.   in an AppleEvent Print event.
  4293.   INPUTS:    none
  4294.   OUTPUTS:    none
  4295.   ERRORS:
  4296.   SIDE EFFECTS:
  4297. }
  4298. VAR wndwObjSpec:    AEDesc;
  4299.     index:            LongInt;
  4300. BEGIN
  4301.   { create an object specifier for the front window }
  4302.   index := 1;
  4303.   IF CheckErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,index,wndwObjSpec) , 2013) 
  4304.       THEN EXIT(DoMenuPrint); 
  4305.     
  4306.   { now send the event }
  4307.   SendAEPrintDoc(wndwObjSpec,TRUE);    { use print dialog }
  4308.   
  4309.   { dispose of obj spec }
  4310.   gTempBool := CheckErr(   AEDisposeDesc(wndwObjSpec) , 2019 );
  4311. END;    { DoMenuPrint }
  4312.  
  4313.  
  4314. {$S QuillNew}
  4315. PROCEDURE DoMenuPrintFile;
  4316. { get a file from the user and print it (by sending yourself the 
  4317.   AppleEvent).
  4318. INPUTS:        none
  4319. OUTPUTS:    none
  4320. ERRORS:
  4321. SIDE EFFECTS:
  4322. }
  4323. VAR myTypeList:    SFTypeList;
  4324.     mySFReply:    StandardFileReply;
  4325.     fileDesc:    AEDesc;
  4326. BEGIN
  4327.   myTypeList[0] := 'QUIL';
  4328.   StandardGetFile(NIL,1,myTypeList,mySFReply);
  4329.   IF NOT mySFReply.sfGood THEN EXIT(DoMenuPrintFile);    { user cancelled }
  4330.   { change it into a descriptor }
  4331.   IF CheckErr(   AECreateDesc(typeFSS,@mySFReply.sfFile,SizeOf(mySFReply.sfFile),fileDesc) , 2113 )
  4332.       THEN EXIT(DoMenuPrintFile);
  4333.   { send it to yourself }
  4334.   SendAEPrintDoc(fileDesc,FALSE);    { don't use print dialog }
  4335.   gTempBool := CheckErr(   AEDisposeDesc(fileDesc) , 2114 );
  4336. END;    { DoMenuPrintFile }
  4337.  
  4338. {$S QuillNew }
  4339. PROCEDURE DoMenuQuit;
  4340. { send a Quit event to myself with the "ask user" option
  4341.   INPUTS:    none
  4342.   OUTPUTS:    none
  4343.   SIDE EFFECTS:
  4344.   NOTES:
  4345. }
  4346. BEGIN
  4347.   SendAEQuit(kAEAsk);
  4348. END;    { DoMenuQuit }
  4349.  
  4350. {$S QuillNew }
  4351. PROCEDURE DoMenuQuitNow;
  4352. { send a Quit event to myself with the "don't save" option
  4353.   INPUTS:    none
  4354.   OUTPUTS:    none
  4355.   SIDE EFFECTS:
  4356.   NOTES:
  4357. }
  4358. BEGIN
  4359.   SendAEQuit(kAENo);
  4360. END;    { DoMenuQuitNow }
  4361.  
  4362.  
  4363. {$S QuillNew }
  4364. PROCEDURE DoMenuSave(window: WindowPtr);
  4365. { save the given window to a file.  If the window
  4366.   doc record has a good file spec, use it; o.w.
  4367.   prompt the user for a file.
  4368.   INPUTS:    window        ptr to window to be saved
  4369.   OUTPUTS:    none
  4370.   ERRORS:
  4371.   SIDE EFFECTS:
  4372. }
  4373. BEGIN
  4374.   WITH DocumentPeek(window)^ DO
  4375.     IF docFile.vRefNum = badVRefNum THEN DoMenuSaveAs(window)    { must prompt user }
  4376.     ELSE SendAESave(window,TRUE,docFile);
  4377. END;    { DoMenuSave }
  4378.  
  4379. {$S QuillNew }
  4380. PROCEDURE DoMenuSaveAs(window: WindowPtr);
  4381. { prompt the user for a file and save the window to
  4382.   it (by sending yourself a Save AppleEvent)
  4383.   INPUTS:    window        ptr to window to be saved
  4384.   OUTPUTS:    none
  4385.   ERRORS:
  4386.   SIDE EFFECTS:
  4387.   NOTES:    this routine only returns info on whether the
  4388.               user cancelled or not; it doesn't say whether
  4389.             the file creation (if needed) or the save itself
  4390.             were successful.  In a real application, these would 
  4391.             be important.
  4392. }
  4393. VAR wndwTitle:    Str255;
  4394.     fileSpec:    FSSpec;
  4395. BEGIN
  4396.   GetWTitle(window,wndwTitle);    { to use as default in SF dialog }
  4397.   IF NOT AskForFile(wndwTitle,fileSpec) THEN EXIT(DoMenuSaveAs);    { user cancelled }
  4398.   SendAESave(window,TRUE,fileSpec);
  4399. END;    { DoMenuSaveAs }
  4400.  
  4401. {$S QuillNew}
  4402. PROCEDURE DoMenuStyle(window: WindowPtr; menuItem: INTEGER);
  4403. { this routine implements the actions of the style menu.
  4404.   INPUTS:    window        ptr to the window in question
  4405.               menuItem    item number selected by user
  4406.   OUTPUTS:    none
  4407.   NOTES:    in some cases the action to take (or, at least,
  4408.               the parameter to send with the AppleEvent Set Data
  4409.             call) depends not only on the item selected, but
  4410.             on the current state of the selected text.
  4411. }
  4412. VAR onStyles:    Style;
  4413.     offStyles:    Style;
  4414.     myStyle:    StyleItem;
  4415.     myMode:        INTEGER;
  4416.     myTextInfo:    TextStyle;
  4417. BEGIN
  4418.   onStyles := [];
  4419.   offStyles := [];
  4420.   
  4421.   IF menuItem = iPlain THEN
  4422.     BEGIN
  4423.       offStyles := gAllStyles;    { everything }
  4424.     END
  4425.   ELSE
  4426.     BEGIN
  4427.       { not Plain; if the chosen style item is uniform across the text, }
  4428.       { we must turn it OFF; otherwise ON                               }
  4429.       
  4430.       { so get the style item }
  4431.       CASE menuItem OF
  4432.         iBold:        myStyle := bold;
  4433.         iItalic:    myStyle := italic;
  4434.         iUnderline:    myStyle := underline;
  4435.         iOutline:    myStyle := outline;
  4436.         iShadow:    myStyle := shadow;
  4437.       END;    { CASE }
  4438.       
  4439.       { check uniformity }
  4440.       myMode := doFace;
  4441.       IF TEContinuousStyle(myMode,myTextInfo,DocumentPeek(window)^.docTE) THEN
  4442.         BEGIN
  4443.           { uniform in SOME style (or Plain) - possibly my style }
  4444.           IF myStyle IN myTextInfo.tsFace
  4445.           THEN offStyles := [myStyle]    { myStyle uniform in text, must turn it OFF }
  4446.           ELSE onStyles := [myStyle]    { not uniform in myStyle, turn it on }
  4447.         END
  4448.       ELSE
  4449.         { no uniformity in any style }
  4450.         BEGIN
  4451.           onStyles := [myStyle];
  4452.         END;
  4453.     END;    { of not Plain }
  4454.     
  4455.   { I don't really need all those BEGIN/END's up there, but they make things clearer }
  4456.     
  4457.   { got both sets - so set the style }
  4458.   gTempBool := CheckErr(   SetStyleForSelText(window,onStyles,offStyles) , 17013 );
  4459. END;    { DoMenuStyle }
  4460.  
  4461.  
  4462. {$S QuillNew}
  4463. PROCEDURE DoMyAlert(alertStr: Str255);
  4464. { just put up an alert with the given string }
  4465. BEGIN
  4466.   IF AEInteractWithUser(kNoTimeOut,NIL,NIL) <> noErr THEN EXIT(DoMyAlert);    { **CHECK - will this cause trouble? }
  4467.   ParamText(alertStr, '', '', '');
  4468.   gTempLong := Alert(rUserAlert, NIL);
  4469. END;    { DoMyAlert }
  4470.  
  4471. {$S QuillNew}
  4472. PROCEDURE DoMyErr(theErr: OSErr; placeNum: INTEGER);
  4473. { puts up an alert box with the error num and the placeNum
  4474.   this is a bottleneck subroutine for handling errors.  As
  4475.   currently written, it puts up an alert box with the error num
  4476.   and the placeNum (marking the place in the code where the
  4477.   error occurred).  However, you can change it to do anything 
  4478.   you want:  write the inputs to a file, jump into the debugger,
  4479.   etc.  You can also write tailored versions for particular
  4480.   calling routines, particular errors, etc.
  4481.   INPUTS:    theErr            os err to be reported
  4482.               placeNum        number to mark actual place of error in code; should be unique
  4483.   OUTPUTS:    none
  4484.   ERRORS:
  4485.   SIDE EFFECTS:
  4486.   NOTES:    as written, this routine does return to the calling function
  4487. }
  4488. VAR myErrStr:    Str255;
  4489. BEGIN
  4490.  IF (NOT gShowAllErrs) & gInHandler THEN EXIT(DoMyErr);    { **CHECK - EXPERIMENTAL }
  4491.  IF AEInteractWithUser(kNoTimeOut,NIL,NIL) <> noErr THEN EXIT(DoMyErr); { **CHECK - what should we do here? }
  4492.   myErrStr := Concat('Hey, boys & girls - error #',MyNumToStr(theErr),' at ',MyNumToStr(placeNum));
  4493.   ParamText(myErrStr, '', '', '');
  4494.   gTempLong := Alert(rUserError, NIL);
  4495. END;    { DoMyErr }
  4496.  
  4497. {$S QuillNew2}
  4498. FUNCTION ElemFromAnythingAccessor(wantClass: DescType; container: AEDesc;
  4499.     containerClass: DescType; form: DescType; selectionData: AEDesc;
  4500.     VAR value: AEDesc; theRefCon: LongInt): OSErr;
  4501. { return an arbitrary element (or "item") from a list.  "Element", 
  4502.   here, does NOT refer to "text elements" (such as char, word, etc.) - 
  4503.   and, for that matter, "item" does not refer to comma-separated text.
  4504.   Instead, we're talking about the first element in a list, the second, 
  4505.   etc.  The wantClass is cListElem.
  4506.   
  4507.   This routine overrides (for wantClass = cListElem) the AnythingFromListAccessor,
  4508.   enabling us to get particular elements out of lists.  If we relied on 
  4509.   AnythingFromListAccessor in this case, it would, as always, return a list - 
  4510.   which is not what we're looking for here (unless the given element happens to
  4511.   BE a list . . . .)
  4512.   
  4513.   The value returned by this accessor may be of any type, depending on what's found
  4514.   in the list.
  4515.   
  4516.   08/22/91    BHM        Put in a coercion to list so that this can get the number of elements
  4517.                       in anything (the OSL can hand back a single token, rather than a 1-element
  4518.                     list of tokens; in that case, we want to return that element, no an error)
  4519. }
  4520. LABEL 9;
  4521. VAR myErr:        OSErr;
  4522.     myList:        AEDesc;    
  4523.     elemCount:    LongInt;
  4524.     index:        LongInt;
  4525.     allFlag:    BOOLEAN;
  4526.     zeroFlag:    BOOLEAN;
  4527. BEGIN
  4528.   myErr := accessorErr;
  4529.   InitSomeDescs(@value,@myList,NIL,NIL,NIL);
  4530.   
  4531.   { coerce the container to a list }
  4532.   IF CatchErr(   AECoerceDesc(container,typeAEList,myList) , 21113 , myErr ) THEN GOTO 9;
  4533.     
  4534.   { now on to the element - how is it specified? }
  4535.   IF form = formAbsolutePosition THEN
  4536.     BEGIN
  4537.       { count the elements }
  4538.       IF CatchErr(   AECountItems(myList,elemCount) , 21115 , myErr ) THEN GOTO 9;
  4539.       
  4540.       { get the element index }
  4541.       IF CatchErr(   DecodeOrdinal(selectionData,elemCount,index,allFlag,zeroFlag) , 21116 ,
  4542.           myErr ) THEN GOTO 9;
  4543.           
  4544.       { if it's all, just duplicate the list }
  4545.       IF allFlag THEN
  4546.         BEGIN
  4547.           gTempBool := CatchErr(   AEDuplicateDesc(myList,value) , 21118 , myErr );
  4548.           GOTO 9;
  4549.         END;
  4550.         
  4551.       { no, it's some particular element - get it from the list }
  4552.       gTempBool := CatchErr(   AEGetNthDesc(myList,index,typeWildCard,gReturnedKeywd,value) , 21119 , myErr );
  4553.       
  4554.       GOTO 9;
  4555.     END;    { of formAbsolutePosition }
  4556.     
  4557.   { unsupported naming form }
  4558.   gTempBool := CatchErr(   errAEWrongDataType , 21120 , myErr );
  4559.   
  4560. 9:    { finish up }
  4561.  
  4562.   { NOTE:  in this routine, if you get an error, there's no need to throw away value - }
  4563.   { because, in every path, there's no way to get an error AFTER creating value.  So   }
  4564.   { if you've got an error, value's still null                                         }
  4565.   
  4566.   gTempBool := CheckErr(   AEDisposeDesc(myList) , 21121 );
  4567.  
  4568.   ElemFromAnythingAccessor := myErr;
  4569. END;    { ElemFromAnythingAccessor }
  4570.  
  4571.  
  4572. {$S QuillNew}
  4573. FUNCTION EqualFSSpecs(aFile, bFile:  FSSpec):  BOOLEAN;
  4574. { compare two file specs to see if they're equal.  Ignore case
  4575.   (but not diacriticals) on the names.  Return TRUE if equal,
  4576.   FALSE o.w.
  4577.   INPUTS:    aFile        first file
  4578.               bFile        second file
  4579.   OUTPUTS:    TRUE if equal, FALSE if not
  4580.   ERRORS:
  4581.   SIDE EFFECTS:
  4582. }
  4583. BEGIN
  4584.   EqualFSSpecs := FALSE;
  4585.   WITH aFile DO
  4586.     BEGIN
  4587.       IF vRefNum <> bFile.vRefNum THEN EXIT(EqualFSSpecs);
  4588.       IF parID <> bFile.parID THEN EXIT(EqualFSSpecs);
  4589.       IF NOT EqualString(name,bFile.name,FALSE,TRUE)  { ignore case but not diacriticals }
  4590.         THEN EXIT(EqualFSSpecs);
  4591.     END;
  4592.   EqualFSSpecs := TRUE;
  4593. END;    { EqualFSSpecs }
  4594.  
  4595. {$S QuillNew2}
  4596. PROCEDURE ExtendTextElem(VAR myText: TextToken);
  4597. { given a text token that represents an item or line, extend
  4598.   the text by 1 additional character to include an adjacent
  4599.   delimiter (comma for items, CR for lines) - if there is one
  4600.   (there won't be if the line or item constitutes all the text
  4601.   in its window).  This routine is used when deleting items or
  4602.   lines - we want to "swallow" 1 delimiter with the element.
  4603.   INPUTS:    myText        token for the text; also used to return extended text
  4604.   OUTPUTS:    none
  4605.   NOTES:    (1) ExtendTextElem does NOT check to see if myText is of
  4606.               the right class, or validate it in any way.  Make sure
  4607.             before you call.  The routine is ONLY for items and lines.
  4608.             (See ExtendWord for words.)
  4609.             (2) if there's no room to extend the text (within its window),
  4610.             it's left alone
  4611.             (3) if the text is extended, we change the tokenClass to cText,
  4612.             since the resulting text is no longer - strictly speaking - 
  4613.             an item or line
  4614. }
  4615. BEGIN
  4616.   WITH myText DO
  4617.     BEGIN
  4618.       IF tokenOffset + tokenLength < DocumentPeek(tokenWndw)^.docTE^^.teLength THEN
  4619.         BEGIN
  4620.           { you can extend to the right }
  4621.           tokenLength := tokenLength + 1;
  4622.           tokenClass := cText;
  4623.           EXIT(ExtendTextElem);
  4624.         END;
  4625.     
  4626.       { if you get here, you couldn't extend to the right }
  4627.       IF tokenOffset > 0 THEN
  4628.         BEGIN
  4629.           { you can extend text to the left }
  4630.           tokenOffset := tokenOffset - 1;
  4631.           tokenLength := tokenLength + 1;
  4632.           tokenClass := cText;
  4633.         END;
  4634.         
  4635.     END;    { of WITH myToken }
  4636. END;    { ExtendTextElem }
  4637.  
  4638. {$S QuillNew2}
  4639. PROCEDURE ExtendWord(VAR myText: TextToken);
  4640. { given a text token that represents a word, extend the
  4641.   text by 1 character to the right or left to include 1
  4642.   space - if that's possible.  If there aren't any spaces
  4643.   adjacent to the word (that is, if the word is bounded
  4644.   by CRs and/or the start of the window's text and/or the
  4645.   end of the window's text), we DON'T extend the text.
  4646.   This routine is used when deleting a word - we want to 
  4647.   swallow 1 space with the word.
  4648.   INPUTS:    myText        text token representing the word; also
  4649.                           used to return extended text
  4650.   OUTPUTS:    none
  4651.   NOTES:    (1) ExtendWord does not check to see if the text token
  4652.               is a word, or validate it in any way.  Let the caller 
  4653.             beware.
  4654.             (2) If we do extend the text, we change its class to cText - 
  4655.             it's not really just a word anymore.
  4656. }
  4657. VAR textHndl:    Handle;
  4658.     textLength:    LongInt;
  4659.     endOffP1:    LongInt;
  4660. BEGIN
  4661.   WITH myText DO
  4662.     BEGIN
  4663.     
  4664.       WITH DocumentPeek(tokenWndw)^.docTE^^ DO
  4665.         BEGIN
  4666.           textHndl := hText;
  4667.           textLength := teLength;
  4668.         END;
  4669.       endOffP1 := tokenOffset + tokenLength;    { offset to 1 byte beyond last char in word }
  4670.       
  4671.       IF endOffP1 < DocumentPeek(tokenWndw)^.docTE^^.teLength THEN
  4672.         BEGIN
  4673.           { there's room on the right - but is it a space? }
  4674.           IF Ptr(ORD(textHndl^) + endOffP1)^ = asciiSpace THEN
  4675.             BEGIN
  4676.               { yes }
  4677.               tokenLength := tokenLength + 1; 
  4678.               tokenClass := cText;
  4679.               EXIT(ExtendWord);
  4680.             END;
  4681.         END;    { of room on the right }
  4682.     
  4683.       { if we get here, we were unable to extend to the right }
  4684.       IF tokenOffset > 0 THEN
  4685.         BEGIN
  4686.           { there's room on the left - but is there a space? }
  4687.           IF Ptr(ORD(textHndl^) + tokenOffset - 1)^ = asciiSpace THEN
  4688.             BEGIN
  4689.               { yes }
  4690.               tokenOffset := tokenOffset - 1;
  4691.               tokenLength := tokenLength + 1;
  4692.               tokenClass := cText;
  4693.             END;
  4694.         END;    { of room on the left }
  4695.         
  4696.     END;    { of WITH myText }
  4697.     
  4698. END;    { ExtendWord }
  4699.  
  4700.  
  4701. {$S QuillNew}
  4702. FUNCTION FileToTERec(fileSpec: FSSpec; teHndl: TEHandle): OSErr;
  4703. { open the file and read the text and style info in it into the given
  4704.   new-style TERec.  The file is in the "handle-list" format (see 
  4705.   WriteHandlesToFile and FillHandlesFromFile), specifically:
  4706.       
  4707.     number of data blocks = 6        (2 bytes)
  4708.     size of text block                (4 bytes)
  4709.     text block                        (variable)
  4710.     size of style record block        (4 bytes)
  4711.     style record block                (variable)
  4712.     size of style table block        (4 bytes)
  4713.     style table block                (variable)
  4714.     size of line-height table block    (4 bytes)
  4715.     line-height table block            (variable)
  4716.     size of null-style block        (4 bytes)
  4717.     null-style block                (variable)
  4718.     size of null-scrap block        (4 bytes)
  4719.     null-scrap block                (variable)
  4720.   
  4721.   INPUTS:    fileSpec    FSSpec for file
  4722.               teHndl        handle to new-style TERec
  4723.   OUTPUT:    TRUE if successful, FALSE o.w.
  4724.   ERRORS:
  4725.   SIDE EFFECTS:
  4726.   NOTES:    this version returns an OSErr instead of TRUE/FALSE;
  4727.               it will replace the old one soon
  4728. }
  4729. LABEL 8,9;
  4730. VAR myErr:            INTEGER; 
  4731.     refNum:            INTEGER;
  4732.     teListCount:    INTEGER;
  4733.     teInfoList:        ARRAY[1..6] OF Handle;
  4734.     i:                INTEGER;
  4735.     thisHndl:        Handle;
  4736.     xferCount:        INTEGER;
  4737.     textHndl:        Handle;
  4738.     styleHndl:        TEStyleHandle;
  4739.     
  4740.   PROCEDURE TossHandles;
  4741.   { dispose of all honest handles in the list - this is why I initialized the list to NILs }
  4742.   VAR j:    INTEGER;
  4743.   BEGIN
  4744.     FOR j := 1 TO teListCount DO IF teInfoList[j] <> NIL THEN DisposHandle(teInfoList[j]);
  4745.   END;
  4746.   
  4747. BEGIN { FileToTERec }
  4748.   IF CatchErr(   FSpOpenDF(fileSpec,0,refNum) , 613 , myErr ) THEN GOTO 9;    { must set function value }
  4749.   IF CatchErr(   SetFPos(refNum,fsFromStart,0) , 614 , myErr ) THEN GOTO 8;    { must close file }
  4750.   
  4751.   teListCount := 6;
  4752.   
  4753.   { get 6 handles, each 1 byte long - there's virtually no }
  4754.   { chance of the calls failing, but we'll check anyway    }
  4755.   
  4756.   FOR i := 1 TO teListCount DO teInfoList[i] := NIL;    { safety first }
  4757.   
  4758.   FOR i := 1 to teListCount DO
  4759.     BEGIN
  4760.       thisHndl := NewHandle(1);
  4761.       IF CatchErr(   MemError , 615 , myErr ) THEN
  4762.         BEGIN
  4763.           TossHandles;
  4764.           GOTO 8;
  4765.         END;
  4766.       teInfoList[i] := thisHndl;
  4767.     END;
  4768.     
  4769.   IF CatchErr(   FillHandlesFromFile(teListCount,@teInfoList,refNum,xferCount) , 616 , myErr ) THEN
  4770.     BEGIN
  4771.       TossHandles;
  4772.       GOTO 8;
  4773.     END;
  4774.     
  4775.   { we've read all the data blocks in from the file }
  4776.   
  4777.   { transfer the text }
  4778.   textHndl := teInfoList[1];
  4779.   HLock(textHndl);
  4780.   TESetText(textHndl^,GetHandleSize(textHndl),teHndl);
  4781.   DisposHandle(textHndl);
  4782.   
  4783.   { now set the other handle fields in the style handle }
  4784.   
  4785.   styleHndl := TEStyleHandle(teInfoList[2]);
  4786.   WITH styleHndl^^ DO    { just setting some fields so I don't need to lock it }
  4787.     BEGIN
  4788.       styleTab := STHandle(teInfoList[3]);
  4789.       lhTab := LHHandle(teInfoList[4]);
  4790.       nullStyle := NullSTHandle(teInfoList[5]);
  4791.       nullStyle^^.nullScrap := STScrpHandle(teInfoList[6]);
  4792.     END;
  4793.     
  4794.   { now set the style handle into the teRec }
  4795.   SetStylHandle(styleHndl,teHndl);
  4796.   
  4797.   { all done }
  4798.  
  4799. 8:    { close file }
  4800.   gTempBool := CatchErr(   FSClose(refNum) , 617 , myErr );
  4801.  
  4802. 9:    { set function result }
  4803.   FileToTERec := myErr;
  4804.   
  4805. END;{ FileToTERec }
  4806.  
  4807. {$S QuillNew}
  4808. FUNCTION FillHandlesFromFile(VAR listCount: INTEGER; listPtr: HandleListPtr;
  4809.     refNum: INTEGER; VAR xferCount: INTEGER):  OSErr;
  4810. { this routine reads data reads data from a file into handles in a list.
  4811.   The handles must already exist; the routine will resize them (this saves
  4812.   us some error-handling hassles about which handles need to be disposed).
  4813.   The file was presumably created by WriteHandlesToFile, and has the format
  4814.   
  4815.     number of data blocks in file        INTEGER (2 bytes)
  4816.     size of 1st data block                LongInt (4 bytes)
  4817.     first data block                    variable
  4818.     size of 2nd data block                LongInt (4 bytes)
  4819.     2nd data block                        variable
  4820.     etc.
  4821.   
  4822.   A "data block", here, is a variable-length stream of contiguous bytes in
  4823.   the file, meant to be read into a single handle,
  4824.   
  4825.   The list of handles is given by a count and a ptr to the list.  The file
  4826.   must already be open, and is specified by a refNum.  The routine does not
  4827.   close the file.  It returns an error number, noErr if there was none.  It
  4828.   also returns, in the VAR parameter listCount, the number of data blocks the
  4829.   file claimed to contain (i.e., the "number of data blocks" value in the file);
  4830.   and, in VAR parameter xferCount, the number of blocks that were successfully
  4831.   transferred.  (If we can't even read the data block count, we'll return -1 in
  4832.   xferCount.)
  4833.   
  4834.   FillHandlesFromFile will NOT try to transfer more blocks than
  4835.   either the input listCount (because it would have no place to put them) or
  4836.   the "number of data blocks" value (because the file says there aren't that
  4837.   many in it).
  4838.   
  4839.   INPUTS:    listCount        number of handles in list; also return VAR for 
  4840.                               number of data blocks in file
  4841.             listPtr            ptr to list of handles
  4842.             refNum            refNum of the file
  4843.             xferCount        return VAR for the number of data blocks transferred
  4844.   OUTPUTS:    error number (noErr if everything is all right)
  4845.   ERRORS:
  4846.   SIDE EFFECTS:
  4847.   NOTES:    all handles must enter this routine unlocked; they will be returned unlocked
  4848. }
  4849. LABEL 8;
  4850. VAR sizeLength:    LongInt;
  4851.     myErr:        OSErr;
  4852.     blockCount:    INTEGER;
  4853.     i:            INTEGER;
  4854.     dataSize:    LongInt;
  4855.     dataHndl:    Handle;
  4856. BEGIN
  4857.   { read the data block count }
  4858.   sizeLength := SizeOf(blockCount);    { 2 bytes, but we need it in a var }
  4859.   IF CatchErr(   FSRead(refNum,sizeLength,@blockCount) , 1413 , myErr ) THEN
  4860.     BEGIN
  4861.       xferCount := -1;    { couldn't even read the data block count }
  4862.       FillHandlesFromFile := myErr;
  4863.       EXIT(FillHandlesFromFile);
  4864.     END;
  4865.     
  4866.   { if you get this far, myErr is already set to noErr }
  4867.   
  4868.   IF listCount > blockCount THEN listCount := blockCount;    { that cuts it down to size }
  4869.   FOR i := 1 to listCount DO
  4870.     BEGIN
  4871.       { read the data block size }
  4872.       sizeLength := SizeOf(dataSize);    { 4 bytes, we need it in a var }
  4873.       IF CatchErr(   FSRead(refNum,sizeLength,@dataSize) , 1414 , myErr ) THEN 
  4874.         BEGIN
  4875.           xferCount := i-1;
  4876.           GOTO 8;    { leave loop on error }
  4877.         END;
  4878.         
  4879.       { size the handle }
  4880.       dataHndl := listPtr^[i];
  4881.       SetHandleSize(dataHndl,dataSize);
  4882.       IF CatchErr(   MemError , 1415 , myErr ) THEN
  4883.         BEGIN
  4884.           xferCount := i-1;
  4885.           GOTO 8;    { leave loop on error }
  4886.         END;
  4887.       { read the data block }
  4888.       HLock(dataHndl);
  4889.       myErr := FSRead(refNum,dataSize,dataHndl^);
  4890.       HUnlock(dataHndl);    { before checking for error }
  4891.       { NOW check for error }
  4892.       IF CheckErr(   myErr , 1416 ) THEN
  4893.         BEGIN
  4894.           xferCount := i-1;
  4895.           GOTO 8;    { leave loop on error }
  4896.         END;
  4897.         
  4898.     END;    { of FOR loop }
  4899.     
  4900.     { got through the loop okay }
  4901.     xferCount := listCount;
  4902.     
  4903. 8:
  4904.   FillHandlesFromFile := myErr;
  4905. END;    { FillHandlesFromFile }
  4906.  
  4907. {$S QuillNew}
  4908. FUNCTION GetDataFromAppProp(appPropDesc: AEDesc; VAR propDataDesc: AEDesc): OSErr;
  4909. { given a descriptor which represents a prop of the app - and which
  4910.   should be of, or coercible to, typeMyAppProp - return a descriptor 
  4911.   containing the data corresponding to that property (using the 
  4912.   property's "best" data type)
  4913.   INPUTS:    appPropDesc            a descriptor for a property of the app.  Must
  4914.                                   be of, or coercible to, typeMyAppProp
  4915.             propDataDesc        return VAR for the data for the prop
  4916.   OUTPUTS:    error code (noErr if none)
  4917.   NOTES:
  4918.       09/16/91    BHM        formerly GetPropForApp
  4919.     02/17/92    BHM        added pUserSelection
  4920. }
  4921. LABEL 9;
  4922. VAR myErr:        OSErr;
  4923.     myAppProp:    DescType;
  4924.     window:        WindowPtr;
  4925.     myErrMode:    DescType;
  4926. BEGIN
  4927.   myErr := genericErr;
  4928.   propDataDesc := gNullDesc;
  4929.   
  4930.   { which prop? }
  4931.   IF CatchErr(   MyAECoerceDescPtr(appPropDesc,typeMyAppProp,@myAppProp,
  4932.       SizeOf(myAppProp),gActSize) , 18413 , myErr ) THEN GOTO 9;
  4933.       
  4934.   IF myAppProp = pUserSelection THEN
  4935.     BEGIN
  4936.       window := FrontWindow;
  4937.       IF window = NIL THEN
  4938.         BEGIN
  4939.           gTempBool := CatchErr(   errAENoUserSelection , 18414 , myErr );
  4940.           GOTO 9;
  4941.         END;
  4942.         
  4943.       { make obj spec for user selection }
  4944.       gTempBool := CatchErr(   SmartMakeSelTextObj(window,propDataDesc) , 18415 , myErr );
  4945.       GOTO 9;
  4946.     END;    { pUserSelection }
  4947.     
  4948.   IF myAppProp = pErrMode THEN
  4949.     BEGIN
  4950.       { get the current mode }
  4951.       IF gShowAllErrs THEN myErrMode := kShowAllErrs
  4952.       ELSE myErrMode := kShowFewErrs;
  4953.       
  4954.       { return descriptor for it }
  4955.       gTempBool := CatchErr(   AECreateDesc(typeEnumerated,@myErrMode,SizeOf(myErrMode),propDataDesc) , 
  4956.           18416 , myErr );
  4957.       GOTO 9;
  4958.     END;    { pErrMode }
  4959.     
  4960.   { if we get to here, we don't know about the prop }
  4961.   gTempBool := CatchErr(   errAEWrongDataType , 18417 , myErr );
  4962.   
  4963. 9:
  4964.   { note - since the creation of propDataDesc is always the last thing you do before }
  4965.   { coming here (if you create it at all), there's no reason to dispose of it even   }
  4966.   { in the error case                                                                }
  4967.   
  4968.   GetDataFromAppProp := myErr;
  4969. END;    { GetDataFromAppProp }
  4970.  
  4971.  
  4972. {$S QuillNew }
  4973. FUNCTION GetFileAndSaveWndw(window: WindowPtr; useFS: BOOLEAN; VAR fileSpec: FSSpec): OSErr;
  4974. { save a window to a file if at all possible.  If useFS is TRUE,
  4975.   use the given file spec; if useFS is FALSE, then get a file
  4976.   spec using MyMakeFSSForWndw (which first looks in the window
  4977.   doc record for a file spec, and, if that fails, concocts one
  4978.   out of the window title and default directory and path).  The
  4979.   file spec you wind up using should be returned in fileSpec.  
  4980.   (If the call fails, fileSpec should be marked as invalid by
  4981.   setting its vRefNum to badVRefNum.)  Create the file if necessary.
  4982.   Don't interact with the user, and overwrite an existing file if 
  4983.   you have to.
  4984.  
  4985.   Th-th-th-that's all, folks!
  4986.   
  4987.   INPUTS:    window        ptr to the window to be saved
  4988.               useFS        if TRUE, use fileSpec as input to determine file to save to;
  4989.                         if FALSE, only use fileSpec for return info
  4990.             fileSpec    result VAR for file spec you wound up using; also, if useFS
  4991.                         is TRUE, use fileSpec as the file to save to; ALSO, if the call
  4992.                         fails, mark fileSpec as invalid (vRefNum = badVRefNum) for safety
  4993.   OUTPUTS:    error code (noErr if none)
  4994.   ERRORS:
  4995.   SIDE EFFECTS:
  4996.   NOTES:    (1) this routine does not "mark" the file doc record with the result
  4997.                   fileSpec
  4998.             (2) it does not tell you whether the file already existed or not.
  4999.             We may want a smarter version in the future.
  5000. }
  5001. LABEL 8,9;
  5002. VAR myErr:        OSErr;
  5003.     tempErr:    OSErr;
  5004. BEGIN
  5005.   myErr := noErr;    { we'll set an error later if we have to }
  5006.   
  5007.   { should we use fileSpec or get one elsewhere? }
  5008.     
  5009.   IF NOT useFS THEN    { get one elsewhere }
  5010.       IF CatchErr(   MyMakeFSSForWndw(window,fileSpec) , 6713 , myErr ) THEN GOTO 8;    { error exit - mark fileSpec as invalid }
  5011.   
  5012.   { now we have a file spec }
  5013.   { create the file; this will give us a dupFNErr if the file already exists, which is ok }
  5014.   
  5015.   tempErr := FSpCreate(fileSpec,'quil','QUIL',smSystemScript);    { smSystemScript = system script }
  5016.   
  5017.   IF (tempErr <> noErr) & (tempErr <> dupFNErr) THEN
  5018.     BEGIN
  5019.       { unexpected error with file creation }
  5020.       gTempBool := CatchErr(   tempErr , 6714 , myErr );
  5021.       GOTO 8;
  5022.     END;
  5023.     
  5024.   { NOTE:  if you want to worry about telling the caller that the file already
  5025.            existed, or about overwriting an existing file, or about changing the
  5026.            existing file so it has the right type et al, this is the place to do 
  5027.            it.  For now, I'm not going to bother. }
  5028.   
  5029.   { got the file spec, file exists - so save already! }
  5030.   IF NOT CatchErr(   TERecToFile(DocumentPeek(window)^.docTE,fileSpec) , 6715 , myErr ) THEN GOTO 9;    { good exit }
  5031.   
  5032. 8:    { error exit - mark fileSpec as invalid }
  5033.   fileSpec.vRefNum := badVRefNum;
  5034.   
  5035. 9:    { set function value }
  5036.   IF myErr = noErr THEN CleanWindow(window);
  5037.   GetFileAndSaveWndw := myErr;
  5038. END;    { GetFileAndSaveWndw }
  5039.  
  5040. {$S QuillNew }
  5041. FUNCTION GetInteractMode(theAppleEvent: AppleEvent; VAR interMode: LongInt): OSErr;
  5042. { return the interact mode level from the AppleEvent.  It should be kAENeverInteract,
  5043.   kAECanInteract, or kAEAlwaysInteract.  If the call fails, it's undefined.
  5044.   INPUTS:    theAppleEvent        AppleEvent to get the interact mode from
  5045.               interMode            result VAR to return the mode in
  5046.   OUTPUTS:    error code (noErr if none)
  5047. }
  5048. LABEL 9;
  5049. VAR returnedType:    DescType;
  5050.     actSize:        Size;
  5051.     myErr:            OSErr;
  5052. BEGIN
  5053.   interMode := 0;
  5054.   IF CatchErr(   AEGetAttributePtr(theAppleEvent,keyInteractLevelAttr,typeLongInteger,returnedType,
  5055.       @interMode,SizeOf(interMode),actSize), 20213 , myErr) THEN GOTO 9;    { must set function value }
  5056.       
  5057.   IF (interMode <> kAENeverInteract) & (interMode <> kAECanInteract) & (interMode <> kAEAlwaysInteract)
  5058.       THEN gTempBool := CatchErr(  errAEUnknownSendMode , 20214 , myErr ); 
  5059.     
  5060. 9:    { set function value }
  5061.   GetInteractMode := myErr;
  5062. END;    { GetInteractMode }
  5063.  
  5064. {$S QuillNew }
  5065. FUNCTION GetObjSpecFields(theObjSpec: AEDesc; VAR theClass: DescType; VAR theCont: AEDesc;
  5066.     VAR theKeyForm: AEKeyword; VAR theKeyData: AEDesc): OSErr;
  5067. { given a desc for an object specifier, break it down into its 4 constituent parts
  5068.   INPUTS:    theObjSpec        the object specifier descriptor; must be of typeObjectSpecifier
  5069.               theClass        result VAR for desired class (a DescType)
  5070.             theCont            result VAR for container, as a desc (can be of many types)
  5071.             theKeyForm        result VAR for the key form (an AEKeyword? **CHECK)
  5072.             theKeyData        result VAR for key data, as a desc (can be of any type)
  5073.   OUTPUTS:    error code (noErr if none)
  5074.   SIDE EFFECTS:    if the call returns noErr, the caller is rersponsible for disposing
  5075.                   of theCont and theKeyData descriptors
  5076.   NOTES:    this new version returns the class and the key form directly, instead of 
  5077.               as descriptors
  5078. }
  5079. LABEL 9;
  5080. VAR myErr:            OSErr;
  5081.     myObjSpecRec:    AEDesc;
  5082. BEGIN
  5083.   myErr := genericErr;
  5084.   
  5085.   InitSomeDescs(@theCont,@theKeyData,@myObjSpecRec,NIL,NIL);
  5086.   
  5087.   { make sure it's of typeObjectSpecifier }
  5088.   IF theObjSpec.descriptorType <> typeObjectSpecifier THEN
  5089.     BEGIN
  5090.       myErr := errAEWrongDataType;
  5091.       DoMyErr(myErr,11013);
  5092.       GOTO 9;    { must clean up and set function value }
  5093.     END;
  5094.     
  5095.   { coerce it to typeAERecord to get at the object fields }
  5096.   IF CatchErr(   AECoerceDesc(theObjSpec,typeAERecord,myObjSpecRec) , 11014 , myErr )
  5097.       THEN GOTO 9;
  5098.       
  5099.   { get the 4 fields }
  5100.   IF CatchErr(   AEGetKeyPtr(myObjSpecRec,keyAEDesiredClass,typeType,gTempType,@theClass,
  5101.       SizeOf(theClass),gTempLong) , 11015 , myErr ) THEN GOTO 9;
  5102.       
  5103.   IF CatchErr(   AEGetKeyDesc(myObjSpecRec,keyAEContainer,typeWildCard,theCont) , 11016 ,
  5104.       myErr ) THEN GOTO 9;
  5105.       
  5106.   IF CatchErr(   AEGetKeyPtr(myObjSpecRec,keyAEKeyForm,typeEnumerated,gTempType,@theKeyForm,
  5107.       SizeOf(theKeyForm),gTempLong) , 11017 , myErr ) THEN GOTO 9;
  5108.       
  5109.   IF CatchErr(   AEGetKeyDesc(myObjSpecRec,keyAEKeyData,typeWildCard,theKeyData) , 11018 , 
  5110.       myErr ) THEN GOTO 9;
  5111.       
  5112.   { everything looks fine }
  5113.   myErr := noErr;
  5114.   
  5115. 9:    { finish up }
  5116.   IF myErr = noErr THEN gTempBool := CheckErr(   AEDisposeDesc(myObjSpecRec) , 11019 )
  5117.   ELSE gTempBool := CheckErr(   DisposeSomeDescs(@theCont,@theKeyData,@myObjSpecRec,NIL,NIL) , 11020 );
  5118.   
  5119.   GetObjSpecFields := myErr;
  5120. END;    { GetObjSpecFields }
  5121.  
  5122. {$S QuillNew2}
  5123. FUNCTION GetDataFromToken(myToken: AEDesc; reqTypesList: AEDesc; 
  5124.     VAR dataDesc: AEDesc; VAR notToken: BOOLEAN): OSErr;
  5125. { given one of my private tokens, return the data corresponding
  5126.   to it, using a requested data type.  If reqType is typeWildCard,
  5127.   use the token's default type.
  5128.   
  5129.   Actually, we now accept a LIST of requested types; we work down
  5130.   the list and use the first type we can cast the data to.  If we
  5131.   find typeWildCard, we use the token's default type; if we find typeBest,
  5132.   we use the token's "best" (i.e., "richest") type.
  5133.   
  5134.   We are basically assuming that there exists for each token a "best" type, 
  5135.   which can, at the very least, be coerced into the token's default type - 
  5136.   as well as any other types we consider legitimate for the token.  If this
  5137.   assumption is broken, we may need to do some restructuring of the code.
  5138.   
  5139.   INPUTS:    myToken            the token
  5140.               reqTypesList    prioritized list of requested types for the returned
  5141.                             data.  NOTE:  a null desc or an empty list will be
  5142.                             treated as typeWildCard.
  5143.             dataDesc        return VAR for the data
  5144.             notToken        return VAR: TRUE if myToken is not one of my
  5145.                             private tokens, FALSE o.w.  This is valid even
  5146.                             if GetDataFromToken returns an error
  5147.   OUTPUTS:    error code (noErr if none)
  5148.   NOTES:    **CHECK - QUESTIONS:
  5149.               (1) should we only accept explicit tokens, or should we try to
  5150.             coerce? (For now, we'll only accept tokens)
  5151.             (2) what should notToken be if we get a token that we can't (currently)
  5152.             get data on?  (notToken = FALSE in this case; it's still a token)
  5153.             (3) should we go directly to token records here, or settle for the
  5154.             descriptors? (right now, we're using the descriptors)
  5155.             (4) should reqType be handled here, or passed on down to the lower-level
  5156.             routines? (we'll do it here for now)
  5157.             
  5158.             Note that this is not intended for descriptors of typeObjectSpecifier,
  5159.             and that it does not handle lists.  That's intentional.
  5160.             
  5161.   01/24/92    BHM        (1) All the "Get...Data" routines below (GetDataFromWndwProp,
  5162.                     GetStylTextData, etc.) are now spec'ed to return "typeBest"
  5163.                     data rather than default type - which, interestingly enough,
  5164.                     didn't require any changes in those routines.  There are changes
  5165.                     to this routine, however, to get the coercion to requested
  5166.                     type(s) right
  5167.                     (2) Changed to accept list of requested types
  5168. }
  5169. LABEL 9;
  5170. VAR myErr:        OSErr;
  5171.     myType:        DescType;
  5172.     bestType:    DescType;
  5173.     defType:    DescType;
  5174.     newDesc:    AEDesc;    
  5175. BEGIN
  5176.   myErr := genericErr;
  5177.   InitSomeDescs(@dataDesc,@newDesc,NIL,NIL,NIL);
  5178.   
  5179.   myType := myToken.descriptorType;
  5180.   
  5181.   { let's get notToken taken care of right away }
  5182.   notToken := (myType <> typeMyWndw) & (myType <> typeMyDoc) & (myType <> typeMyText)
  5183.       & (myType <> typeMyWndwProp) & (myType <> typeMyTextProp) & (myType <> typeMyAppProp);
  5184.   
  5185.   IF myType = typeMyWndwProp THEN
  5186.     BEGIN
  5187.       gTempBool := CatchErr(   GetDataFromWndwProp(myToken,newDesc) , 20513 , myErr );
  5188.       GOTO 9;
  5189.     END;
  5190.     
  5191.   IF myType = typeMyText THEN
  5192.     BEGIN
  5193.       gTempBool := CatchErr(   GetStylTextData(myToken,newDesc) , 20514 , myErr );
  5194.       GOTO 9;
  5195.     END;
  5196.     
  5197.   IF myType = typeMyTextProp THEN
  5198.     BEGIN
  5199.       gTempBool := CatchErr(   GetDataFromTextProp(myToken,newDesc) , 20515 , myErr );
  5200.       GOTO 9;
  5201.     END;
  5202.     
  5203.   IF myType = typeMyAppProp THEN
  5204.     BEGIN
  5205.       gTempBool := CatchErr(   GetDataFromAppProp(myToken,newDesc) , 20516 , myErr );
  5206.       GOTO 9;
  5207.     END;
  5208.     
  5209.   { nothing we know how to get the data of }
  5210.   myErr := errAEWrongDataType;    { or whatever }
  5211.   
  5212. 9:    { finish up }
  5213.  
  5214.   IF myErr = noErr THEN
  5215.     BEGIN
  5216.       myErr := GetWildTypes(myToken,bestType,defType);
  5217.       IF myErr = noErr THEN myErr := MatchToReqList(newDesc,reqTypesList,bestType,defType,dataDesc);
  5218.     END;
  5219.  
  5220.   gTempBool := CheckErr(   AEDisposeDesc(newDesc) , 20517 );
  5221.   
  5222.   GetDataFromToken := myErr;
  5223. END;    { GetDataFromToken }
  5224.  
  5225. {$S QuillNew2}
  5226. FUNCTION GetDataFromTokenList(myList: AEDesc; reqTypesList: AEDesc; 
  5227.     VAR dataList: AEDesc): OSErr;
  5228. { this routine takes a "token list" and returns a corresponding
  5229.   "data list".  The elements of the token list may themselves be
  5230.   lists or tokens, but the ultimate "node elements" have to be
  5231.   tokens (not raw data).  
  5232.   INPUTS:    myList            the "token list"
  5233.               reqTypesList    prioritized list of requested types (we'll 
  5234.                             try them one at a time until we get one that
  5235.                             works - see GetDataFromToken).  NOTE:  null
  5236.                             desc or empty list will be treated as typeWildCard
  5237.             dataList        return VAR for data list
  5238.   OUTPUTS:    error code (noErr if none)
  5239.   NOTES:    01/24/92    BHM        now handles lists of requested types
  5240. }
  5241. LABEL 9;
  5242. VAR myErr:        OSErr;
  5243.     itemCount:    LongInt;
  5244.     i:            LongInt;
  5245.     thisItem:    AEDesc;
  5246.     dataDesc:    AEDesc;
  5247.     notToken:    BOOLEAN;
  5248. BEGIN
  5249.   myErr := genericErr;
  5250.   InitSomeDescs(@dataList,@thisItem,@dataDesc,NIL,NIL);
  5251.   
  5252.   { count the items }
  5253.   IF CatchErr(   AECountItems(myList,itemCount) , 20613 , myErr ) THEN GOTO 9;
  5254.   
  5255.   { make the return list }
  5256.   IF CatchErr(   AECreateList(NIL,0,FALSE,dataList) , 20614 , myErr ) THEN GOTO 9;
  5257.   
  5258.   IF itemCount = 0 THEN GOTO 9;    { empty list }
  5259.   
  5260.   { loop through the items }
  5261.   FOR i := 1 TO itemCount DO
  5262.     BEGIN
  5263.       { get the item }
  5264.       IF CatchErr(   AEGetNthDesc(myList,i,typeWildCard,gReturnedKeywd,thisItem) , 20615 ,
  5265.           myErr ) THEN GOTO 9;
  5266.           
  5267.       { if it's a list, call myself recursively }
  5268.       IF thisItem.descriptorType = typeAEList THEN
  5269.         BEGIN
  5270.           IF CatchErr(   GetDataFromTokenList(thisItem,reqTypesList,dataDesc) , 20616 , myErr )
  5271.               THEN GOTO 9;
  5272.         END
  5273.       ELSE
  5274.         BEGIN
  5275.           { otherwise assume it's a token }
  5276.           IF CatchErr(   GetDataFromToken(thisItem,reqTypesList,dataDesc,notToken) , 20617 , myErr )
  5277.               THEN GOTO 9;
  5278.         END;
  5279.         
  5280.       { add the data desc to the end of the list }
  5281.       IF CatchErr(   AEPutDesc(dataList,0,dataDesc) , 20618 , myErr ) THEN GOTO 9;
  5282.       
  5283.       { dispose of this item and data desc }
  5284.       gTempBool := CheckErr(   DisposeSomeDescs(@thisItem,@dataDesc,NIL,NIL,NIL) , 20621);
  5285.       InitSomeDescs(@thisItem,@dataDesc,NIL,NIL,NIL);    { just for neatness }
  5286.     END;    { of FOR loop }
  5287.     
  5288. 9:    { finish up }
  5289.   
  5290.   { only dispose of data list in error case - it may have been created before an error occurred }
  5291.   IF myErr <> noErr THEN gTempBool := CheckErr(   AEDisposeDesc(dataList) , 20619 );
  5292.   
  5293.   gTempBool := CheckErr(   DisposeSomeDescs(@thisItem,@dataDesc,NIL,NIL,NIL) , 20620 );
  5294.   
  5295.   GetDataFromTokenList := myErr;
  5296. END;    { GetDataFromTokenList }
  5297.  
  5298.  
  5299. {$S QuillNew}
  5300. FUNCTION GetDataFromTextProp(textPropDesc: AEDesc; VAR propDataDesc: AEDesc): OSErr;
  5301. { given a descriptor which represents a prop of some text - and which 
  5302.   should be, or be coercible to, typeMyTextProp - return a descriptor 
  5303.   containing the data corresponding to that property (using the property's
  5304.   "best" data type).
  5305.   INPUTS:    textPropDesc    a descriptor for the property of the text.
  5306.                               Must already be typeMyTextProp, or at least
  5307.                             coercible to it.
  5308.             propDataDesc    return VAR for the data for the prop
  5309.   OUTPUTS:    error code (noErr if none)
  5310.   NOTES:    (1) later it may be necessary to separate the part of this 
  5311.               routine that gets the text prop token from the part that
  5312.             actually goes after the prop value (but maybe not)
  5313.             (2) currently I am returning fonts as descriptors of typeMyFont,
  5314.             which is just a short integer with a fancy type.  This is not,
  5315.             properly speaking, the default data type (which is typeChar).
  5316.             This gets fixed up at HandleGetData, but really we need to
  5317.             divide the code up differently.  See HandleGetData for more
  5318.             information.
  5319.             
  5320.             09/16/91    BHM        formerly GetPropForTextDesc
  5321.             09/16/91    BHM        fonts are now of typeChar, nothing else
  5322. }
  5323. LABEL 9;
  5324. VAR myErr:            OSErr;
  5325.     myTextProp:        TextPropToken;
  5326.     myStyle:        TextStyle;
  5327.     myLineHeight:    INTEGER;
  5328.     myFontAscent:    INTEGER;
  5329.     myProp:            DescType;
  5330.     mySize:            INTEGER;
  5331.     fontName:        Str255;
  5332.     wndwTE:            TEHandle;
  5333.     onStyles:        Style;
  5334.     offStyles:        Style;
  5335.     myOffset:        LongInt;
  5336. BEGIN
  5337.   myErr := genericErr;    { or whatever }
  5338.   propDataDesc := gNullDesc;
  5339.   
  5340.   IF CatchErr(   MyAECoerceDescPtr(textPropDesc,typeMyTextProp,@myTextProp,
  5341.       SizeOf(myTextProp),gActSize) , 16213 , myErr ) THEN GOTO 9;
  5342.       
  5343.   
  5344.   WITH myTextProp DO
  5345.     BEGIN
  5346.       TEGetStyle(tpText.tokenOffset,myStyle,myLineHeight,myFontAscent,
  5347.           DocumentPeek(tpText.tokenWndw)^.docTE);
  5348.       myProp := tpProp;
  5349.     END;
  5350.     
  5351.   IF myProp = pPointSize THEN
  5352.     BEGIN
  5353.       mySize := myStyle.tsSize;
  5354.       { **CHECK - how do I get the application font size? }
  5355.       IF mySize = 0 THEN mySize := 12;    { this way for now . . . }
  5356.       gTempBool :=  CatchErr(   AECreateDesc(typeShortInteger,@mySize,SizeOf(mySize),propDataDesc) , 
  5357.           16214 , myErr );
  5358.       GOTO 9;
  5359.     END;
  5360.     
  5361.   IF myProp = pFont THEN
  5362.     BEGIN
  5363.       GetFontName(myStyle.tsFont,fontName);
  5364.       gTempBool := CatchErr(   StrToTextDesc(fontName,propDataDesc) , 16217 , myErr );
  5365.       GOTO 9;
  5366.     END;
  5367.     
  5368.   IF myProp = pTextStyles THEN
  5369.     BEGIN
  5370.       onStyles := myStyle.tsFace;
  5371.       offStyles := gAllStyles - onStyles;
  5372.       gTempBool := CatchErr(   StyleSetsToStyleDesc(onStyles,offStyles,propDataDesc,TRUE,TRUE) , 16220 , myErr );
  5373.       GOTO 9;
  5374.     END;
  5375.     
  5376.   IF myProp = pUniformStyles THEN
  5377.     BEGIN
  5378.       { first, select text }
  5379.       WITH myTextProp.tpText DO
  5380.         BEGIN
  5381.           wndwTE := DocumentPeek(tokenWndw)^.docTE;
  5382.           TESetSelect(tokenOffset,tokenOffset + tokenLength,wndwTE);
  5383.         END;
  5384.         
  5385.       { then, get uniform styles }
  5386.       IF CatchErr(   MyGetUniformStyles(wndwTE,onStyles,offStyles) , 16215 , myErr ) THEN GOTO 9;   
  5387.       gTempBool := CatchErr(   StyleSetsToStyleDesc(onStyles,offStyles,propDataDesc,TRUE,TRUE) , 16216 , myErr );
  5388.       GOTO 9;
  5389.     END;
  5390.  
  5391.   IF myProp = pLength THEN
  5392.     BEGIN
  5393.       gTempBool := CatchErr(   AECreateDesc(typeLongInteger,@myTextProp.tpText.tokenLength,SizeOf(myTextProp.tpText.tokenLength),
  5394.           propDataDesc) , 16218 , myErr );
  5395.       GOTO 9;
  5396.     END;
  5397.     
  5398.   IF myProp = pOffset THEN
  5399.     BEGIN
  5400.       myOffset := myTextProp.tpText.tokenOffset + 1;    { **CHECK - do we want the "+1"? }
  5401.       gTempBool := CatchErr(   AECreateDesc(typeLongInteger,@myOffset,SizeOf(myOffset),
  5402.           propDataDesc) , 16219 , myErr );
  5403.       GOTO 9;
  5404.     END;
  5405.     
  5406.     
  5407.   { not a property we can handle right now }
  5408.   myErr := errAEWrongDataType;
  5409.   
  5410. 9:    { finish up }
  5411.   GetDataFromTextProp := myErr;
  5412. END;    { GetDataFromTextProp }
  5413.  
  5414. {$S QuillNew}
  5415. FUNCTION GetDataFromWndwProp(wndwPropDesc: AEDesc; VAR propDataDesc: AEDesc): OSErr;
  5416. { given a descriptor which represents a prop of a window - and which should
  5417.   already be of typeMyWndwProp - return a descriptor containing the data
  5418.   corresponding to that property (using the property's "best" type).
  5419.   INPUTS:    wndwPropDesc        a descriptor representing the a property of a
  5420.                                   window.  Usually, when this routine is called, 
  5421.                                 the desc is already of typeMyWndwProp.  At the
  5422.                                 very least, it must be coercible to that type.
  5423.             propDataDesc        return VAR for the data corresponding to the prop
  5424.   OUTPUTS:    error code (noErr if none)
  5425.   NOTES:    this routine actually just grabs the window prop token out of its
  5426.               descriptor and calls GetWindowProp
  5427.             09/16/91    BHM        formerly GetPropForWndwDesc
  5428. }
  5429. LABEL 9;
  5430. VAR myErr:        OSErr;
  5431.     myWndwProp:    WndwPropToken;
  5432. BEGIN
  5433.   myErr := genericErr;    { or whatever }
  5434.   propDataDesc := gNullDesc;
  5435.   
  5436.   IF CatchErr(   MyAECoerceDescPtr(wndwPropDesc,typeMyWndwProp,@myWndwProp,
  5437.       SizeOf(myWndwProp),gActSize) , 14913 , myErr ) THEN GOTO 9;
  5438.       
  5439.   WITH myWndwProp DO
  5440.     BEGIN
  5441.       IF CatchErr(   GetWindowProp(wpWndw,wpProp,propDataDesc) , 14914 , myErr )
  5442.           THEN GOTO 9;
  5443.     END;
  5444.     
  5445. 9:    { finish up }
  5446.   GetDataFromWndwProp := myErr;
  5447. END;    { GetDataFromWndwProp }
  5448.  
  5449. {$S QuillNew2}
  5450. FUNCTION GetSingularData(srcDesc: AEDesc; reqType: DescType; VAR dataDesc: AEDesc): OSErr;
  5451. { this routine takes a descriptor and returns it as data of a requested type.
  5452.   The input descriptor can either be raw data or an object specifier; if it's
  5453.   an object specifier, it can only resolve to a single token, not a list of
  5454.   tokens.  (This is what's needed - right now, at least - for the Set Data event.)
  5455.   If the requested type is typeWildCard, we return either a duplicate of the input
  5456.   data (if it's raw data) or use the object's default data type (if it's an object).
  5457.   INPUTS:    srcDesc        original descriptor - can be either raw data or an object specifier
  5458.                           (resolving to a single object)
  5459.             reqType        requested type
  5460.             dataDesc    return VAR for data to be returned
  5461.   OUTPUTS:    error code (noErr if none)
  5462.   NOTES:    DON'T give this a (private) token; it would probably return it as data.
  5463.               All it knows about are object specifiers and raw data.
  5464.   01/24/92    BHM        modified to use new GetDataFromToken, which takes a LIST of req types,
  5465.                       rather than just one (this routine still only takes one, however, which
  5466.                     we stuff into a 1-element list)
  5467. }
  5468. LABEL 9;
  5469. VAR myErr:            OSErr;
  5470.     newDesc:        AEDesc;
  5471.     reqTypesList:    AEDesc;
  5472.     notToken:        BOOLEAN;    { we ignore this }
  5473. BEGIN
  5474.   myErr := genericErr;
  5475.   InitSomeDescs(@dataDesc,@newDesc,@reqTypesList,NIL,NIL);
  5476.   
  5477.   IF srcDesc.descriptorType = typeObjectSpecifier THEN
  5478.     BEGIN
  5479.       IF CatchErr(   AEResolve(srcDesc,kAEIDoMinimum,newDesc) , 21013 , myErr ) THEN GOTO 9;
  5480.       
  5481.       { stuff the req type into a 1-element list } { this isn't really necessary in the typeWildCard case . . . . }
  5482.       IF CatchErr(   AECreateList(NIL,0,FALSE,reqTypesList) , 21017 , myErr ) THEN GOTO 9;
  5483.       IF CatchErr(   AEPutPtr(reqTypesList,0,typeType,@reqType,SizeOf(reqType)) , 21018 , myErr )
  5484.           THEN GOTO 9;
  5485.       
  5486.       { the next step, in addition to getting data when possible, will reject lists }
  5487.       gTempBool := CatchErr(   GetDataFromToken(newDesc,reqTypesList,dataDesc,notToken) , 21014 , myErr );
  5488.       
  5489.       GOTO 9;
  5490.     END;
  5491.     
  5492.   { if it gets here, it's raw data - is it even worth checking against my token types? }
  5493.   gTempBool := CatchErr(   AECoerceDesc(srcDesc,reqType,dataDesc) , 21015 , myErr );
  5494.   
  5495. 9:    { finish up }
  5496.   gTempBool := CheckErr(   DisposeSomeDescs(@newDesc,@reqTypesList,NIL,NIL,NIL) , 21016 );
  5497.   
  5498.   GetSingularData := myErr;
  5499. END;    { GetSingularData }
  5500.  
  5501. {$S QuillNew2}
  5502. FUNCTION GetStyleItemFromConst(myConst: DescType; VAR stylItem: StyleItem; 
  5503.     VAR plainFlag: BOOLEAN):  BOOLEAN;
  5504. { this routine takes a typeEnumerated value and checks to see if it's a
  5505.   style item constant (kAEBold, kAEUnderline, etc. - possibly kAEPlain).
  5506.   If it isn't, we return FALSE; if it is, we return the corresponding 
  5507.   style item.  If the value is kAEPlain, we return TRUE in the plainFlag
  5508.   (and stylItem is undefined); if it's some other style item constant,
  5509.   we return FALSE in the plainFlag
  5510.   INPUTS:    myConst        a typeEnumerated value
  5511.               stylItem    return VAR for the corresponding style item.  Undefined
  5512.                         if myConst is kAEPlain or is not a style item const at all
  5513.             plainFlag    return VAR - TRUE if myConst is kAEPlain, FALSE if myConst
  5514.                         is some other style constant.  Undefined if myConst is not
  5515.                         a style item const at all.
  5516.   OUTPUTS:    TRUE if myConst is a style item const (kAEBold, kAEUnderline, etc. - 
  5517.               possibly kAEPlain), FALSE o.w.
  5518. }
  5519. VAR i:    INTEGER;
  5520. BEGIN
  5521.   IF myConst = kAEPlain THEN
  5522.     BEGIN
  5523.       plainFlag := TRUE;
  5524.       stylItem := bold;    { just some arbitrary value, it's really undefined here }
  5525.       GetStyleItemFromConst := TRUE;
  5526.       EXIT(GetStyleItemFromConst);
  5527.     END;
  5528.     
  5529.   FOR i := 1 TO kNumOfStyles DO
  5530.     BEGIN
  5531.       IF theStyles[i].stylConst = myConst THEN
  5532.         BEGIN
  5533.           { found it in the list }
  5534.           stylItem := theStyles[i].stylItem;
  5535.           plainFlag := FALSE;
  5536.           GetStyleItemFromConst := TRUE;
  5537.           EXIT(GetStyleItemFromConst);
  5538.         END;
  5539.     END;    { of loop }
  5540.     
  5541.   { if we get here, it's not a style item const or kAEPlain }
  5542.   stylItem := bold;    { just some value, really undefined }
  5543.   plainFlag := FALSE;    { ditto }
  5544.   GetStyleItemFromConst := FALSE;
  5545. END;    { GetStyleItemFromConst }
  5546.  
  5547.  
  5548. {$S QuillNew }
  5549. FUNCTION GetStylTextData(textDesc: AEDesc; VAR dataDesc: AEDesc): OSErr;
  5550. { given a text descriptor - which should already be of typeMyText - return
  5551.   a descriptor containing the data (both characters and style info) of that
  5552.   text.  The return desc should be of typeStyledText.
  5553.   INPUTS:    textDesc        descriptor for the text.  Preferably, this should
  5554.                               already be of typeMyText when the routine is called.
  5555.                             At the very least, it MUST be coercible to that type.
  5556.             dataDesc        return VAR for the text's data.  It will be returned
  5557.                             as typeStyledText.
  5558.   OUTPUTS:    error code (noErr if none)
  5559. }
  5560. LABEL 9;
  5561. VAR myErr:    OSErr;
  5562.     myText:    TextToken;
  5563. BEGIN
  5564.   myErr := genericErr;    { or whatever }
  5565.   dataDesc := gNullDesc;
  5566.   
  5567.   IF CatchErr(   MyAECoerceDescPtr(textDesc,typeMyText,@myText,SizeOf(myText),gActSize) ,
  5568.       14813 , myErr ) THEN GOTO 9;    { finish up }
  5569.       
  5570.   { NOTE:  probably MakeStyledTextDesc should be folded into this routine.  But for now we have it }
  5571.       
  5572.   IF CatchErr(   MakeStylTextDesc(myText,dataDesc) , 14814 , myErr ) THEN GOTO 9;
  5573.   
  5574. 9:    { finish up }
  5575.   
  5576.   GetStylTextData := myErr;
  5577. END;    { GetStylTextData }
  5578.  
  5579. {$S QuillNew}
  5580. FUNCTION GetTextFromDesc(srcDesc: AEDesc; VAR dstDesc: AEDesc): OSErr;
  5581. { try a few different things to get the data from a descriptor
  5582.   into text form.
  5583.   INPUTS:    srcDesc        original data
  5584.               dstDesc        return VAR for data in text form
  5585.   OUTPUTS:    error code (noErr if none)
  5586.   NOTES:    This is a hack, and will probably be replaced in 
  5587.               the near future with coercers, accessors, et al.
  5588. }
  5589. LABEL 9;
  5590. VAR myErr:    OSErr;
  5591.     myText:    TextToken;
  5592. BEGIN
  5593.   myErr := genericErr;
  5594.   dstDesc := gNullDesc;
  5595.   
  5596.   { first, just try to coerce it }
  5597.   myErr := AECoerceDesc(srcDesc,typeChar,dstDesc);
  5598.   IF myErr = noErr THEN GOTO 9;    { we're done }
  5599.   
  5600.   { next, try to pick it up as a typeMyText }
  5601.   myErr := MyAECoerceDescPtr(srcDesc,typeMyText,@myText,SizeOf(myText),gActSize);
  5602.   IF myErr = noErr THEN
  5603.     BEGIN
  5604.       { got a text token, make a desc for it }
  5605.       gTempBool := CatchErr(   TextTokenToDesc(myText,dstDesc) , 15613 , myErr );
  5606.       GOTO 9;
  5607.     END;
  5608.     
  5609.   myErr := errAEWrongDataType;
  5610.   
  5611. 9:
  5612.   GetTextFromDesc := myErr;
  5613. END;    { GetTextFromDesc }
  5614.  
  5615.  
  5616. {$S QuillNew}
  5617. FUNCTION GetTextElemFromText(srcText: TextToken; elemClass: DescType; 
  5618.     elemIndex: LongInt; VAR elemText: TextToken): OSErr;
  5619. { given a text token, this routine will pick out a particular
  5620.   char, word, line, or item in it, and return the result as
  5621.   a new text token.
  5622.   INPUTS:    srcText        token describing the original text
  5623.               elemClass    desired class - cChar, cWord, cLine, or cItem
  5624.             elemIndex    position of the element within the text; 1 for
  5625.                         first word (or whatever), 2 for second, etc.
  5626.             elemText    return VAR for token describing the particular element
  5627.   OUTPUTS:    error code; noErr if element is found.  The most common error is
  5628.               errAEIllegalIndex - either there weren't enough of that kind of
  5629.             element, or elemIndex < 1
  5630.   NOTES:    (1) the tokenWndw field of the return elemText token will be the same
  5631.               as the tokenWndw of srcText (in the noErr case).  The tokenOffset field
  5632.             is always from the start of the window, NOT the start of srcText
  5633.             (2) unfortunately we can't do a CASE statement on the elemClass with
  5634.             our current Pascal compiler
  5635.             7/1/91    BHM        Added "spots" to the classes
  5636. }
  5637. LABEL 9;
  5638. VAR myErr:            OSErr;
  5639.     wndwTextHndl:    Handle;
  5640.     srcTextPtr:        Ptr;
  5641.     srcTextLength:    LongInt;
  5642.     delChar:        SignedByte;
  5643.     elemOffset:        LongInt;
  5644.     elemLength:        LongInt;
  5645. BEGIN
  5646.   myErr := errAEIllegalIndex;
  5647.   InitTextToken(elemText);
  5648.   
  5649.   WITH srcText DO
  5650.     BEGIN
  5651.       wndwTextHndl := DocumentPeek(tokenWndw)^.docTE^^.hText;
  5652.       HLock(wndwTextHndl);
  5653.       srcTextPtr := Ptr(ORD(wndwTextHndl^) + tokenOffset);
  5654.       srcTextLength := tokenLength;
  5655.     END;
  5656.   
  5657.   IF (elemClass = cLine) | (elemClass = cItem) THEN
  5658.     BEGIN
  5659.       IF elemClass = cLine THEN delChar := asciiCR
  5660.       ELSE delChar := asciiComma;
  5661.       myErr := MyGetTextElem(srcTextPtr,srcTextLength,delChar,elemIndex,elemOffset,elemLength);
  5662.       GOTO 9;
  5663.     END;
  5664.     
  5665.   IF elemClass = cWord THEN
  5666.     BEGIN
  5667.       myErr := MyGetWord(srcTextPtr,srcTextLength,elemIndex,elemOffset,elemLength);
  5668.       GOTO 9;
  5669.     END;
  5670.     
  5671.   IF elemClass = cChar THEN
  5672.     BEGIN
  5673.       IF (elemIndex < 1) | (elemIndex > srcTextLength) THEN myErr := errAEIllegalIndex
  5674.       ELSE 
  5675.         BEGIN
  5676.           elemOffset := elemIndex - 1;
  5677.           elemLength := 1;
  5678.           myErr := noErr;
  5679.         END;
  5680.       GOTO 9;
  5681.     END;
  5682.     
  5683.   IF elemClass = cSpot THEN
  5684.     BEGIN
  5685.       IF (elemIndex < 1) | (elemIndex > srcTextLength + 1) THEN myErr := errAEIllegalIndex
  5686.       ELSE
  5687.         BEGIN
  5688.           elemOffset := elemIndex - 1;
  5689.           elemLength := 0;
  5690.           myErr := noErr;
  5691.         END;
  5692.       GOTO 9;
  5693.     END;
  5694.     
  5695.     { looks like char and spot cases can be easily combined - **CHECK }
  5696.     
  5697.   { unknown element class }
  5698.   myErr := errAEWrongDataType;
  5699.   
  5700.  9:    { finish up }
  5701.    HUnlock(wndwTextHndl);
  5702.    
  5703.    IF myErr = noErr THEN WITH elemText DO
  5704.      BEGIN
  5705.        tokenClass := elemClass;
  5706.        tokenWndw := srcText.tokenWndw;
  5707.        tokenOffset := srcText.tokenOffset + elemOffset;    { to get proper offset within common window }
  5708.        tokenLength := elemLength;
  5709.      END;
  5710.      
  5711.   GetTextElemFromText := myErr;
  5712. END;    { GetTextElemFromText }
  5713.  
  5714. {$S QuillNew2}
  5715. FUNCTION GetWildTypes(myToken: AEDesc; VAR bestType: DescType; 
  5716.     VAR defType: DescType): OSErr;
  5717. { given a token (of one of my private token types), return the
  5718.   "best type" (which is up to Quill) and the default type (which
  5719.   should match the Registry) for data from that token.
  5720.   INPUTS:    myToken        the token
  5721.               bestType    return VAR for "best type"
  5722.             defType        return VAR for default type
  5723.   OUTPUTS:    error code (noErr if none)
  5724.   NOTES:    (1) if the token represents a property of something, 
  5725.               we will have to (in most cases) "open it up" and look
  5726.             at the particular property to get the types
  5727.             (2) sure wish I could case off of DescTypes!  Probably this 
  5728.             is better done with a table (hashed or otherwise)
  5729.             (3)  IMPORTANT:  the pContents property of windows/docs
  5730.             is not included here because the accessor returns a text 
  5731.             token, which is properly handled below - EXPERIMENTAL - **CHECK
  5732. }
  5733. LABEL 9;
  5734. VAR myErr:        OSErr;
  5735.     myType:        DescType;
  5736.     myWndwProp:    WndwPropToken;
  5737.     myProp:        DescType;
  5738.     myTextProp:    TextPropToken;
  5739.     myAppProp:    DescType;
  5740.  
  5741.     PROCEDURE AssignWildTypes(forBest: DescType; forDef: DescType);
  5742.     { This routine stuffs values into bestType and defType, *and sets
  5743.       myErr to noErr*! (bestType, defType, and myErr are all variables 
  5744.       in the parent routine GetWildTypes)
  5745.       INPUTS:    forBest        value for bestType
  5746.                   forDef        value for defType
  5747.       OUTPUTS:    none
  5748.       NOTES:    wholely owned by GetWildTypes
  5749.     }
  5750.     BEGIN
  5751.       bestType := forBest;
  5752.       defType := forDef;
  5753.       myErr := noErr;
  5754.     END;    { AssignWildTypes }
  5755.     
  5756. BEGIN    { GetWildTypes }
  5757.   myErr := genericErr;
  5758.   bestType := typeWildCard;    { never true }
  5759.   defType := typeWildCard;    { never true }
  5760.   
  5761.   myType := myToken.descriptorType;
  5762.   
  5763.   IF (myType = typeMyWndw) | (myType = typeMyDoc) THEN
  5764.     BEGIN
  5765.       AssignWildTypes(typeObjectSpecifier,typeObjectSpecifier);
  5766.       GOTO 9;
  5767.     END;
  5768.     
  5769.   IF myType = typeMyText THEN
  5770.     BEGIN
  5771.       AssignWildTypes(typeStyledText,typeIntlText);
  5772.       GOTO 9;
  5773.     END;
  5774.     
  5775.   IF myType = typeMyWndwProp THEN
  5776.     BEGIN  { typeMyWndwProp }
  5777.     
  5778.       { get the token }
  5779.       IF CatchErr(   MyAECoerceDescPtr(myToken,typeMyWndwProp,@myWndwProp,
  5780.           SizeOf(myWndwProp),gActSize) , 23713 , myErr ) THEN GOTO 9;
  5781.       myProp := myWndwProp.wpProp;
  5782.       
  5783.       { case off the prop }
  5784.       IF myProp = pBounds THEN AssignWildTypes(typeQDRectangle,typeQDRectangle)
  5785.       ELSE IF myProp = pPosition THEN AssignWildTypes(typeQDPoint,typeQDPoint)
  5786.       ELSE IF myProp = pName THEN AssignWildTypes(typeChar,typeIntlText)
  5787.     {  ELSE IF myProp = pContents THEN AssignWildTypes(typeStyledText,typeIntlText) }    { this is where it would go, if it belonged here }
  5788.       ELSE myErr := errAEWrongDataType;    { don't know about that prop }
  5789.       GOTO 9;
  5790.     END;    { typeMyWndwProp }
  5791.     
  5792.   IF myType = typeMyTextProp THEN
  5793.     BEGIN
  5794.       { get the token }
  5795.       IF CatchErr(   MyAECoerceDescPtr(myToken,typeMyTextProp,@myTextProp,
  5796.           SizeOf(myTextProp),gActSize) , 23714 , myErr ) THEN GOTO 9;
  5797.       myProp := myTextProp.tpProp;
  5798.       
  5799.       { case off the prop }
  5800.       IF myProp = pPointSize THEN AssignWildTypes(typeShortInteger,typeShortInteger)
  5801.       ELSE IF myProp = pFont THEN AssignWildTypes(typeChar,typeChar)
  5802.       ELSE IF (myProp = pTextStyles) | (myProp = pUniformStyles) THEN AssignWildTypes(typeTextStyles,typeTextStyles)
  5803.       ELSE IF (myProp = pLength) | (myProp = pOffset) THEN AssignWildTypes(typeLongInteger,typeLongInteger)
  5804.       ELSE myErr := errAEWrongDataType;    { don't know about that prop }
  5805.       GOTO 9;
  5806.     END;    { typeMyTextProp }
  5807.     
  5808.   IF myType = typeMyAppProp THEN
  5809.     BEGIN
  5810.       { get the prop }
  5811.       IF CatchErr(   MyAECoerceDescPtr(myToken,typeMyAppProp,@myProp,SizeOf(myProp),gActSize),
  5812.           23715 , myErr ) THEN GOTO 9;
  5813.           
  5814.       IF myProp = pErrMode THEN AssignWildTypes(typeEnumerated,typeEnumerated)
  5815.       ELSE IF myProp = pUserSelection THEN AssignWildTypes(typeStyledText,typeObjectSpecifier)
  5816.       ELSE myErr := errAEWrongDataType;    { don't know about that prop }
  5817.     END;    { typeMyAppProp }
  5818.     
  5819. 9:
  5820.   GetWildTypes := myErr;
  5821. END;    { GetWildTypes }
  5822.  
  5823. {$S QuillNew }
  5824. FUNCTION GetWindowProp(window: WindowPtr; theProp: DescType; 
  5825.     VAR dataDesc: AEDesc): OSErr;
  5826. { given a window and a property, return the value of the property
  5827.   for that window in a descriptor, using the prop's default type
  5828.   INPUTS:    window            ptr to the window
  5829.               theProp            the property
  5830.             propDataDesc    return VAR for the property value
  5831.   OUTPUTS:    error code (noErr if none)
  5832.   ERRORS:
  5833.   SIDE EFFECTS:
  5834.   NOTES:    09/10/91    BHM        Just cleaned it up a little
  5835.               01/31/92    BHM        Added pVisible, pIndex, pIsModal, pIsResizable,
  5836.                                 pHasTitleBar, pIsModified
  5837.             02/17/92    BHM        IMPORTANT:  pContents does not appear here because
  5838.                                 the accessor returns a text token, which is handled 
  5839.                                 by GetStylTextData.  EXPERIMENTAL - **CHECK
  5840.               **CHECK - I can imagine situations where would would have to know the
  5841.               requested type down at this low level - but those situations do not
  5842.             apply to any window properties.  (The situation is:  the default type 
  5843.             loses some information, and there are valid requested types that can't
  5844.             be reconstructed/coerced from the default type.)
  5845. }
  5846. LABEL 9;
  5847. VAR myRect:        Rect;
  5848.     myErr:        OSErr;
  5849.     myPoint:    Point;
  5850.     wndwTitle:    Str255;
  5851.     myText:        TextToken;
  5852.     myDesc:        AEDesc;
  5853.     myIndex:    LongInt;
  5854.     boolProp:    BOOLEAN;
  5855.     myBool:        BOOLEAN;
  5856. BEGIN
  5857.   myErr := genericErr;
  5858.   InitSomeDescs(@dataDesc,@myDesc,NIL,NIL,NIL);
  5859.  
  5860.   IF theProp = pBounds THEN
  5861.     BEGIN
  5862.       myRect := WindowPeek(window)^.strucRgn^^.rgnBBox;    { don't need to lock the handle just for getting the rect }
  5863.       gTempBool := CatchErr(   AECreateDesc(typeQDRectangle,@myRect,SizeOf(myRect),dataDesc) ,
  5864.       9713 , myErr );
  5865.       GOTO 9;    { finish up }
  5866.     END;
  5867.     
  5868.   IF theProp = pPosition THEN
  5869.     BEGIN
  5870.       myPoint := WindowPeek(window)^.strucRgn^^.rgnBBox.topLeft;
  5871.       gTempBool := CatchErr(   AECreateDesc(typeQDPoint,@myPoint,SizeOf(myPoint),dataDesc) , 
  5872.           9714 , myErr );
  5873.       GOTO 9;
  5874.     END;
  5875.     
  5876.   IF theProp = pName THEN
  5877.     BEGIN
  5878.       GetWTitle(window,wndwTitle);
  5879.       gTempBool := CatchErr(   StrToTextDesc(wndwTitle,dataDesc) , 9715 , myErr );
  5880.       GOTO 9;
  5881.     END;    { IF pName }
  5882.     
  5883.   IF theProp = pIndex THEN
  5884.     BEGIN
  5885.       myIndex := IndexFromWndwPtr(window);
  5886.       gTempBool := CatchErr(   AECreateDesc(typeLongInteger,@myIndex,SizeOf(myIndex),dataDesc) , 
  5887.           9718 , myErr );
  5888.       GOTO 9;
  5889.     END;
  5890.     
  5891.   { let's group all the boolean properties together }
  5892.   boolProp := TRUE;    { assume for now }
  5893.   IF theProp = pVisible THEN myBool := WindowPeek(window)^.visible        { all my windows are visible, but I'll do it the hard way for illustration }
  5894.   ELSE IF theProp = pIsModal THEN myBool := FALSE                        { none of my windows are modal }
  5895.   ELSE IF theProp = pIsResizable THEN myBool := TRUE                    { all are resizeable }
  5896.   ELSE IF theProp = pHasTitleBar THEN myBool := TRUE                    { all have title bar }
  5897.   ELSE IF theProp = pIsModified THEN myBool := DocumentPeek(window)^.dirtyFlag
  5898.   ELSE boolProp := FALSE;
  5899.  
  5900.   IF boolProp THEN
  5901.     BEGIN
  5902.       gTempBool := CatchErr(   AECreateDesc(typeBoolean,@myBool,SizeOf(myBool),dataDesc) ,
  5903.           9717 , myErr );
  5904.       GOTO 9;
  5905.     END;
  5906.     
  5907.   { if we get to here, it's not a prop we know }
  5908.   myErr := errAECantHandleClass;    { or whatever - **CHECK }
  5909.     
  5910. 9:
  5911.   { note - never an error after creating dataDesc, so we don't have to dispose of it even in the error case }
  5912.   gTempBool := CheckErr(   AEDisposeDesc(myDesc) , 9721 );
  5913.   
  5914.   GetWindowProp := myErr;
  5915. END;    { GetWindowProp }
  5916.  
  5917. {$S QuillNew }
  5918. FUNCTION GotRequiredParams(theAppleEvent: AppleEvent):  OSErr;
  5919. { checks the AppleEvent to see if we've gotten all the required
  5920.   parameters; returns noErr if yes, errAEParamMissed if no,
  5921.   or passes along some other error if one occurs
  5922.   INPUTS:    theAppleEvent        AppleEvent to be checked
  5923.   OUTPUTS:    as described above
  5924.   ERRORS:
  5925.   SIDE EFFECTS:
  5926. }
  5927. VAR myErr:            OSErr;
  5928.     returnedType:    DescType;
  5929.     actSize:        Size;
  5930. BEGIN
  5931.   { look for the keyMissedKeywordAttr, just to see if it's there }
  5932.   myErr := AEGetAttributePtr(theAppleEvent,keyMissedKeywordAttr,typeWildCard,returnedType,NIL,0,actSize);
  5933.   IF myErr = errAEDescNotFound THEN GotRequiredParams := noErr            { attribute not there means we got all req params }
  5934.   ELSE IF myErr = noErr THEN GotRequiredParams := errAEParamMissed        { attribute there means missed at least one }
  5935.   ELSE GotRequiredParams := myErr;    { some unexpected arror in looking for the attribute }
  5936. END;    { GotReqiredParams }
  5937.  
  5938. {$S QuillNew2}
  5939. FUNCTION GrowKeyBuffer:  BOOLEAN;
  5940. { tries to grow the key buffer by a set amount
  5941.   INPUTS:    none
  5942.   OUTPUTS:    TRUE if succeeds, FALSE o.w. (mem error)
  5943. }
  5944. BEGIN
  5945.   GrowKeyBuffer := FALSE;
  5946.   WITH keyBuffer DO
  5947.     BEGIN
  5948.       SetHandleSize(Handle(bufChars),bufSize + kBufGrowAmount);
  5949.       IF MemError <> noErr THEN EXIT(GrowKeyBuffer);
  5950.       bufSize := bufSize + kBufGrowAmount;
  5951.     END;
  5952.   GrowKeyBuffer := TRUE;
  5953. END;  { GrowKeyBuffer }
  5954.  
  5955.  
  5956. {$S QuillNew}
  5957. FUNCTION HandleClose(theAppleEvent: AppleEvent; reply: AppleEvent;
  5958.     handlerRefCon: LongInt): OSErr;
  5959. { close the object or objects represented by the direct parameter.
  5960.   For "dirty" objects, an optional parameter determines whether the
  5961.   app should save them without interacting (kAEYes), not save them
  5962.   (kAENo), or ask the user on each one (kAEAsk).  If kAEYes, there
  5963.   may also be an optional destination file parameter - but there can
  5964.   only be one of them (we don't permit a list), so you better be closing
  5965.   only one thing.  If no destination file is specified, the application 
  5966.   uses defaults.
  5967. }
  5968. LABEL 9;
  5969. VAR myErr:            OSErr;
  5970.     myDirObj:        AEDesc;
  5971.     saveOpt:        DescType;
  5972.     myFSSpec:        FSSpec;
  5973.     gotFileParam:    BOOLEAN;
  5974.     resDesc:        AEDesc;
  5975. BEGIN
  5976.   PreHandler;
  5977.   myErr := genericErr;
  5978.   InitSomeDescs(@myDirObj,@resDesc,NIL,NIL,NIL);
  5979.   
  5980.   { get the direct object }
  5981.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeObjectSpecifier,myDirObj) , 
  5982.       5713 , myErr ) THEN GOTO 9;
  5983.       
  5984.   { get optional save param, if any }
  5985.   saveOpt := kAEAsk;    { the default }
  5986.   myErr := AEGetParamPtr(theAppleEvent,keyAESaveOptions,typeEnumerated,gReturnedType,
  5987.       @saveOpt,SizeOf(saveOpt),gActSize);
  5988.   IF myErr = errAEDescNotFound THEN myErr := noErr    { optional parameter not found - not an error }
  5989.   ELSE IF CheckErr(   myErr , 5714 ) THEN GOTO 9;
  5990.   
  5991.   IF saveOpt = kAEYes THEN
  5992.     BEGIN
  5993.       { check for optional destination file parameter }
  5994.       myErr := AEGetParamPtr(theAppleEvent,keyAEDestination,typeFSS,gReturnedType,
  5995.           @myFSSpec,SizeOf(myFSSpec),gActSize);
  5996.       gotFileParam := (myErr = noErr);
  5997.       IF myErr = errAEDescNotFound THEN myErr := noErr
  5998.       ELSE IF CheckErr(   myErr , 5715 ) THEN GOTO 9;
  5999.     END;
  6000.     
  6001.   { make sure we got all required params }
  6002.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 5716 , myErr ) THEN GOTO 9;
  6003.   
  6004.   { resolve the direct object }
  6005.   IF CatchErr(   AEResolve(myDirObj,kAEIDoMinimum,resDesc) , 5717 , myErr )
  6006.       THEN GOTO 9;
  6007.       
  6008.   { now close - we dispatch on list vs. token}
  6009.   IF resDesc.descriptorType = typeAEList
  6010.   THEN gTempBool := CatchErr(   CloseTokenList(resDesc,saveOpt,gotFileParam,myFSSpec) , 5718 , myErr )
  6011.   ELSE gTempBool := CatchErr(   CloseToken(resDesc,saveOpt,gotFileParam,myFSSpec) , 5719 , myErr );
  6012.   
  6013. 9:
  6014.   gTempBool := CheckErr(   DisposeSomeDescs(@myDirObj,@resDesc,NIL,NIL,NIL) , 5720 );
  6015.   HandleClose := myErr;
  6016.   PostHandler(reply,myErr);
  6017. END;    { HandleClose }
  6018.  
  6019.  
  6020.  
  6021. {$S QuillNew}
  6022. FUNCTION HandleCopy(theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr;
  6023. LABEL 9;
  6024. VAR myErr:            OSErr;
  6025.     window:            WindowPtr;
  6026. BEGIN
  6027.   PreHandler;
  6028.   IF CatchErr(   SetUpEdit(theAppleEvent,window) , 17813 , myErr ) THEN GOTO 9;
  6029.   
  6030.   { got the selection, so cut; pass any errors to the client (**CHECK) }
  6031.   gTempBool := CatchErr(   MyDoCopy(window) , 17814 , myErr );
  6032.   
  6033. 9:    { finish up }
  6034.   HandleCopy := myErr;
  6035.   PostHandler(reply,myErr);
  6036. END;    { HandleCopy }
  6037.  
  6038. {$S QuillNew}
  6039. FUNCTION HandleCountElements(theAppleEvent: AppleEvent; reply: AppleEvent;
  6040.     handlerRefCon: LongInt): OSErr;
  6041. LABEL 9;
  6042. VAR myErr:        OSErr;
  6043.     myDirObj:    AEDesc;
  6044.     myClass:    DescType;
  6045.     myCount:    LongInt;
  6046. BEGIN
  6047.   PreHandler;
  6048.   myErr := errAEEventNotHandled;
  6049.   myDirObj := gNullDesc;
  6050.   
  6051.   { pick up direct object, which is the container in which things are to be counted }
  6052.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeWildCard,myDirObj) , 17913 ,
  6053.       myErr ) THEN GOTO 9;
  6054.       
  6055.   { now the class of objects to be counted }
  6056.   IF CatchErr(   AEGetParamPtr(theAppleEvent,keyAEObjectClass,typeType,gReturnedType,@myClass,SizeOf(myClass),gActSize) , 
  6057.       17914 , myErr ) THEN GOTO 9;
  6058.       
  6059.   { missing any parameters? }
  6060.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 17915 , myErr ) THEN GOTO 9;
  6061.   
  6062.   { now count }
  6063.   IF CatchErr(   RealCountProc(myClass,myDirObj,myCount) , 17916 , myErr ) THEN GOTO 9;
  6064.   
  6065.   { add result to reply }
  6066.   IF reply.descriptorType <> typeNull THEN 
  6067.       gTempBool := CatchErr(   AEPutParamPtr(reply,keyDirectObject,typeLongInteger,@myCount,SizeOf(myCount)) ,
  6068.           17917 , myErr );
  6069.           
  6070. 9:    { finish up }
  6071.  
  6072.   gTempBool := CheckErr(   AEDisposeDesc(myDirObj) , 17918 );
  6073.   
  6074.   HandleCountElements := myErr;
  6075.   PostHandler(reply,myErr);
  6076. END;    { HandleCountElements }
  6077.  
  6078. {$S QuillNew}
  6079. FUNCTION HandleCreateElement(theAppleEvent: AppleEvent; reply: AppleEvent;
  6080.     handlerRefCon: LongInt): OSErr;
  6081. { make a new element, placed as specified by the insertion loc.  Right now
  6082.   we only create new windows (or documents) within the null container; and
  6083.   we ignore any initial data or initial prop data suppled.  This will get
  6084.   more sophisticated in the future.
  6085.   
  6086.   Based on the old HandleNewElement.  This needs to be split up a little.
  6087. }
  6088. LABEL 9;
  6089. VAR myErr:            OSErr;
  6090.     newElemClass:    DescType;
  6091.     insertionLoc:    AEDesc;
  6092.     relObjToken:    AEDesc;
  6093.     position:        DescType;
  6094.     relWndw:        WindowPtr;
  6095.     newWndw:        WindowPtr;
  6096.     newPos:            DescType;
  6097.     index:            LongInt;
  6098.     wndwObjSpec:    AEDesc;
  6099. BEGIN
  6100.   PreHandler;
  6101.   myErr := genericErr;
  6102.   InitSomeDescs(@insertionLoc,@relObjToken,@wndwObjSpec,NIL,NIL);
  6103.   
  6104.   { pick up the class of the new element }
  6105.   IF CatchErr(   AEGetParamPtr(theAppleEvent,keyAEObjectClass,typeType,gReturnedType,
  6106.       @newElemClass,SizeOf(newElemClass),gActSize) , 22913 , myErr ) THEN GOTO 9;
  6107.       
  6108.   { pick up the insertion loc }
  6109.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyAEInsertHere,typeInsertionLoc,insertionLoc) , 
  6110.       22914 , myErr ) THEN GOTO 9;
  6111.       
  6112.   { check for missing required parameters }
  6113.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 22915 , myErr ) THEN GOTO 9;
  6114.   
  6115.   { is it a class we can handle? }
  6116.   IF (newElemClass <> cWindow) & (newElemClass <> cDocument) THEN
  6117.     BEGIN
  6118.       gTempBool := CatchErr(   errAEWrongDataType , 22916 , myErr );
  6119.       GOTO 9;
  6120.     END;
  6121.   
  6122.   { decode the insertion loc }
  6123.   IF CatchErr(   DecodeInsertionLoc(insertionLoc,relObjToken,position) , 22917 , myErr )
  6124.       THEN GOTO 9;
  6125.       
  6126.   { two cases:  beginning/end, or before/after/replace }
  6127.   IF (position = kAEBeginning) | (position = kAEEnd) THEN
  6128.     BEGIN
  6129.       { beginning or end - rel obj better be null desc }
  6130.       IF relObjToken.descriptorType <> typeNull THEN
  6131.         BEGIN
  6132.           gTempBool := CatchErr(   errAEWrongDataType , 22918 , myErr );
  6133.           GOTO 9;
  6134.         END;
  6135.         
  6136.       { so - beginning or end of null container }
  6137.       
  6138.       { two cases - no windows yet, or 1 or more windows }
  6139.       relWndw := FrontWindow;
  6140.       IF relWndw = NIL THEN
  6141.         BEGIN
  6142.           { no windows yet; create one }
  6143.           gTempBool := CatchErr(   MyNewWindow(newWndw) , 22919 , myErr ); 
  6144.           { **CHECK - actually, the entire kAEBeginning case can be folded in here, whether there are windows already or not }
  6145.           GOTO 9;
  6146.         END;
  6147.       { there's 1 or more windows - set up inputs for MySendWindow }
  6148.       
  6149.       { we've already set up relWndw as the front window - correct as necessary }
  6150.       IF position = kAEEnd THEN relWndw := BackWindow;
  6151.       
  6152.       { set up a position for MySendWindow }
  6153.       IF position = kAEBeginning THEN newPos := kAEBefore ELSE newPos := kAEAfter;
  6154.       
  6155.       { and fall into MySendWindow . . . }
  6156.       { that is:  if we get here, then we're in the beginning/end case, 1 or more }
  6157.       { windows already exists, and we're set up for MySendWindow - after we get  }
  6158.       { a new window                                                              }
  6159.     END  { beginning/end case }
  6160.     
  6161.   ELSE  { before/after/into case }
  6162.     BEGIN
  6163.       { get the "relative" window }
  6164.       IF CatchErr(   MyAECoerceDescPtr(relObjToken,typeMyWndw,@relWndw,SizeOf(relWndw),gActSize) , 
  6165.           22920 , myErr ) THEN GOTO 9;
  6166.           
  6167.       { set newPos }
  6168.       newPos := position;
  6169.       
  6170.       { and fall into MySendWindow . . . }
  6171.       { if we get here, we're set up for MySendWindow - after we get a new window }
  6172.     END;    { before/after/into case }
  6173.     
  6174.   { so get a new window already! }
  6175.   IF CatchErr(   MyNewWindow(newWndw) , 22921 , myErr ) THEN GOTO 9;
  6176.   
  6177.   { and move it to its rightful place }
  6178.   gTempBool := CatchErr(   MySendWindow(newWndw,relWndw,newPos) , 22922 , myErr );
  6179.   
  6180. 9:
  6181.   { there's a few cases for clean-up }
  6182.   
  6183.   IF (myErr = noErr) & (reply.descriptorType <> typeNull) THEN
  6184.     BEGIN
  6185.       { must return an obj spec for the new window }
  6186.       index := IndexFromWndwPtr(newWndw);
  6187.       gTempBool := CatchErr(   MakeObjSpecFromIndex(newElemClass,gNullDesc,index,wndwObjSpec) , 22923 , myErr );
  6188.       IF myErr = noErr THEN
  6189.           gTempBool := CatchErr(   AEPutParamDesc(reply,keyDirectObject,wndwObjSpec) , 22924 , myErr );
  6190.     END;    { of attaching a reply if need be }
  6191.     
  6192.   gTempBool := CheckErr(   DisposeSomeDescs(@insertionLoc,@relObjToken,@wndwObjSpec,NIL,NIL) , 22925 );
  6193.   
  6194.   HandleCreateElement := myErr; 
  6195.   PostHandler(reply,myErr);
  6196. END;    { HandleCreateElement }
  6197.  
  6198. {$S QuillNew}
  6199. FUNCTION HandleCut(theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr;
  6200. LABEL 9;
  6201. VAR myErr:            OSErr;
  6202.     window:            WindowPtr;
  6203. BEGIN
  6204.   PreHandler;
  6205.   IF CatchErr(   SetUpEdit(theAppleEvent,window) , 17113 , myErr ) THEN GOTO 9;
  6206.   
  6207.   { got the selection, so cut; pass any errors to the client (**CHECK) }
  6208.   gTempBool := CatchErr(   MyDoCut(window) , 17114 , myErr );
  6209.   
  6210. 9:    { finish up }
  6211.   HandleCut := myErr;
  6212.   PostHandler(reply,myErr);
  6213. END;    { HandleCut }
  6214.  
  6215. {$S QuillNew2}
  6216. FUNCTION HandleDeleteElement(theAppleEvent: AppleEvent; reply: AppleEvent;
  6217.     handlerRefCon: LongInt): OSErr;
  6218. LABEL 9;
  6219. VAR myErr:        OSErr;
  6220.     myDirObj:    AEDesc;
  6221. BEGIN
  6222.   PreHandler;
  6223.   myErr := errAEEventNotHandled;
  6224.   myDirObj := gNullDesc;
  6225.   
  6226.   { pick up direct object, which is the thing to be deleted }
  6227.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeWildCard,myDirObj) , 21513 , myErr )
  6228.       THEN GOTO 9;
  6229.       
  6230.   { missing any parameters? }
  6231.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 21514 , myErr ) THEN GOTO 9;
  6232.   
  6233.   { now delete }
  6234.   myErr := DeleteThisObj(myDirObj);
  6235.   
  6236. 9:    { finish up }
  6237.   gTempBool := CheckErr(   AEDisposeDesc(myDirObj) , 21515 );
  6238.   
  6239.   HandleDeleteElement := myErr;
  6240.   PostHandler(reply,myErr);
  6241. END;    { HandleDeleteElement }
  6242.  
  6243. {$S QuillNew2}
  6244. FUNCTION HandleDoObjectsExist(theAppleEvent: AppleEvent; reply: AppleEvent;
  6245.     handlerRefCon: LongInt): OSErr;
  6246. LABEL 9;
  6247. VAR myErr:        OSErr;
  6248.     myDirObj:    AEDesc;
  6249.     resDesc:    AEDesc;
  6250.     myBool:        BOOLEAN;
  6251. BEGIN
  6252.   PreHandler;
  6253.   myErr := genericErr;
  6254.   InitSomeDescs(@myDirObj,@resDesc,NIL,NIL,NIL);
  6255.   
  6256.   { pick up the direct object }
  6257.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeObjectSpecifier,myDirObj) , 
  6258.       24413 , myErr ) THEN GOTO 9;
  6259.       
  6260.   { see if you can resolve it }
  6261.   myBool := (AEResolve(myDirObj,kAEIDoMinimum,resDesc) = noErr);
  6262.   
  6263.   { if they want a reply - and they SHOULD - return the result }
  6264.   IF reply.descriptorType <> typeNull THEN
  6265.       gTempBool := CatchErr(   AEPutParamPtr(reply,keyAEResult,typeBoolean,@myBool,SizeOf(myBool)) , 
  6266.           24414 , myErr );
  6267.           
  6268.   { that was easy! }
  6269.   
  6270. 9:
  6271.   gTempBool := CheckErr(   DisposeSomeDescs(@myDirObj,@resDesc,NIL,NIL,NIL) , 24415 );
  6272.   
  6273.   HandleDoObjectsExist := myErr;
  6274.   PostHandler(reply,myErr);
  6275. END;    { HandleDoObjectsExist }
  6276.  
  6277. {$S QuillNew}
  6278. FUNCTION HandleGetData(theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr;
  6279. { 09/16/91    BHM        rewritten to handle token lists better
  6280.   01/24/92    BHM        now accepts lists of requested types
  6281. }
  6282. LABEL 9;
  6283. VAR myErr:            OSErr;
  6284.     myDirObj:        AEDesc;
  6285.     reqType:        DescType;
  6286.     reqTypesList:    AEDesc;
  6287.     newDesc:        AEDesc;
  6288.     notToken:        BOOLEAN;    { really, we ignore this one }
  6289.     dataDesc:        AEDesc;
  6290. BEGIN
  6291.   PreHandler;
  6292.   myErr := errAEEventNotHandled;
  6293.   InitSomeDescs(@myDirObj,@dataDesc,@reqTypesList,NIL,NIL);
  6294.   
  6295.   { pick up the direct object }
  6296.   
  6297.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeWildCard,myDirObj) , 
  6298.       14613 , myErr ) THEN GOTO 9;    { finish up }
  6299.       
  6300.   { get a requested return type list, if any }
  6301.   myErr := AEGetParamPtr(theAppleEvent,keyAERequestedType,typeAEList,gReturnedType,
  6302.       @reqType,SizeOf(reqType),gActSize);
  6303.       
  6304.   { NOTE: all lower-level routines treat a reqTypesList of typeNull as though it }
  6305.   { were a 1-element list containing typeWildCard, so we don't have to hoke up   }
  6306.   { a 1-element list here                                                        }
  6307.       
  6308.   IF myErr = errAEDescNotFound THEN myErr := noErr
  6309.   ELSE IF myErr <> noErr THEN
  6310.     BEGIN
  6311.       { unexpected problem while trying to get param }
  6312.       gTempBool := CheckErr(   myErr , 14614 );
  6313.       GOTO 9;
  6314.     END;
  6315.     
  6316.   { check for required parameters }
  6317.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 14615 , myErr ) THEN GOTO 9;
  6318.   
  6319.   { now, get the data }
  6320.   
  6321.   { I'll do this fairly explicitly }
  6322.   { the direct object has to be an object specifier }
  6323.   IF CatchErr(   AEResolve(myDirObj,kAEIDoMinimum,newDesc) , 14620 , myErr ) THEN GOTO 9;
  6324.   
  6325.   { the resolved object is either a token or a "token list" }
  6326.   IF newDesc.descriptorType = typeAEList THEN
  6327.     BEGIN
  6328.       { it's a list }
  6329.       IF CatchErr(   GetDataFromTokenList(newDesc,reqTypesList,dataDesc) , 14621 , myErr ) THEN GOTO 9;
  6330.     END
  6331.   ELSE
  6332.     BEGIN
  6333.       { it better be a token }
  6334.       IF CatchErr(   GetDataFromToken(newDesc,reqTypesList,dataDesc,notToken) , 14622 , myErr ) THEN GOTO 9;
  6335.     END;
  6336.  
  6337.           
  6338.   { if they wanted a reply, attach it now }
  6339.   IF reply.descriptorType <> typeNull THEN    { this means they want a reply - **CHECK }
  6340.       gTempBool := CatchErr(   AEPutParamDesc(reply,keyDirectObject,dataDesc) , 14618 , myErr );
  6341.  
  6342. 9:    { finish up }
  6343.   
  6344.   gTempBool := CheckErr(   DisposeSomeDescs(@myDirObj,@dataDesc,@reqTypesList,NIL,NIL) , 14619 );
  6345.   HandleGetData := myErr;
  6346.   PostHandler(reply,myErr);
  6347. END;    { HandleGetData }
  6348.  
  6349. {$S QuillNew}
  6350. FUNCTION HandleMove(theAppleEvent: AppleEvent; reply: AppleEvent;
  6351.     handlerRefCon: LongInt): OSErr;
  6352. LABEL 9;
  6353. VAR myErr:            OSErr;
  6354.     myDirObj:        AEDesc;
  6355.     insertionLoc:    AEDesc;
  6356.     relObjToken:    AEDesc;
  6357.     position:        DescType;
  6358.     resDesc:        AEDesc;
  6359. BEGIN
  6360.   PreHandler;
  6361.   myErr := genericErr;
  6362.   InitSomeDescs(@myDirObj,@insertionLoc,@relObjToken,NIL,NIL);
  6363.   
  6364.   { pick up the direct object }
  6365.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeObjectSpecifier,myDirObj) , 
  6366.       19013 , myErr ) THEN GOTO 9;
  6367.       
  6368.   { pick up insertion loc }
  6369.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyAEInsertHere,typeInsertionLoc,insertionLoc) , 
  6370.       19014 , myErr ) THEN GOTO 9;
  6371.       
  6372.   { make sure we got all the required params }
  6373.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 19015 , myErr ) THEN GOTO 9;
  6374.       
  6375.   { decode the insertion loc }
  6376.   IF CatchErr(   DecodeInsertionLoc(insertionLoc,relObjToken,position) , 19016 , myErr )
  6377.       THEN GOTO 9;
  6378.       
  6379.   { resolve the direct object }
  6380.   IF CatchErr(   AEResolve(myDirObj,kAEIDoMinimum,resDesc) , 19017 , myErr )
  6381.       THEN GOTO 9;
  6382.       
  6383.   { now move - we dispatch on list vs. token }
  6384.   IF resDesc.descriptorType = typeAEList 
  6385.   THEN gTempBool := CatchErr(   MoveTokenList(resDesc,relObjToken,position) , 19018 , myErr)
  6386.   ELSE gTempBool := CatchErr(   MoveToken(resDesc,relObjToken,position) , 19019 , myErr );
  6387.   
  6388. 9:
  6389.   gTempBool := CheckErr(   DisposeSomeDescs(@myDirObj,@insertionLoc,@relObjToken,NIL,NIL) , 19020 );
  6390.   HandleMove := myErr;
  6391.   PostHandler(reply,myErr);
  6392. END;    { HandleMove }
  6393.  
  6394. {$S QuillNew}
  6395. FUNCTION HandleOpenApp(theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr;
  6396. { check the event for missing required parameters - the Open App Event should have no required
  6397.   parameters at all.  If there are any, or if your call to check them failed, return an error;
  6398.   otherwise return noErr and call MyNewWindow to open an untitled document
  6399. }
  6400. LABEL 9;
  6401. VAR myErr:        OSErr;
  6402. BEGIN
  6403.   PreHandler;
  6404.   myErr := errAEEventNotHandled;
  6405.   
  6406.   { check required params }
  6407.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 20013 , myErr )
  6408.       THEN GOTO 9;    { finish up }
  6409.       
  6410.   { open a new window }  
  6411.   gTempBool := CatchErr(   MyNewWindow(WindowPtr(gTempPtr)) , 20014 , myErr );
  6412.   
  6413. 9:    { finish up }
  6414.   HandleOpenApp := myErr;
  6415.   PostHandler(reply,myErr);
  6416. END;  { HandleOpenApp }
  6417.  
  6418. {$S QuillNew}
  6419. FUNCTION HandleOpenDocs(theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr;
  6420. { get the list of things to be opened, and open them 
  6421.   NOTES:    the official definition of the OpenDocs event says that
  6422.               it takes a list of alias records.  I ask for them as FSSpec's
  6423.             instead; it's more convenient for me, and the AE Manager will
  6424.             do the coercion automatically
  6425. LABEL 9;
  6426. VAR myErr:            INTEGER;
  6427.     docList:        AEDescList;
  6428.     returnedType:    DescType;
  6429.     actSize:        Size;
  6430.     itemCount:        LongInt;
  6431.     i:                INTEGER;
  6432.     myFSSpec:        FSSpec;
  6433.     keywd:            AEKeyWord;
  6434.     itemErr:        INTEGER;
  6435. BEGIN
  6436.   PreHandler;
  6437.   myErr := errAEEventNotHandled;
  6438.   docList := gNullDesc;
  6439.   
  6440.   { pick up the direct object, which is a list of things to be opened }
  6441.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,docList) , 913 , myErr )
  6442.       THEN GOTO 9;    { finish up }
  6443.   
  6444.   { check for missing required parameters }
  6445.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 914 , myErr ) THEN GOTO 9;
  6446.     
  6447.   { count the items in the list }
  6448.   IF CatchErr(   AECountItems(docList,itemCount) , 916 , myErr ) THEN GOTO 9;
  6449.     
  6450.   { for each item, open the associated doc, if possible }
  6451.   FOR i := 1 to itemCount DO
  6452.     BEGIN
  6453.       { get the file }
  6454.       itemErr := AEGetNthPtr(docList,i,typeFSS,keywd,returnedType,@myFSSpec,SizeOf(myFSSpec),actSize);
  6455.       IF itemErr <> noErr THEN DoItemErr(i,itemErr,917)    { couldn't get a file from this item - handle error and go on }
  6456.       ELSE
  6457.         BEGIN
  6458.           itemErr := MyOpenWindow(myFSSpec);
  6459.           IF itemErr <> noErr THEN DoItemErr(i,itemErr,918)    { couldn't open the file for this item - handle and go on }
  6460.         END;
  6461.     END; { of FOR }
  6462.     
  6463.   { everything looks fine }
  6464.   myErr := noErr;
  6465.  
  6466. 9:    { finish up }    
  6467.   gTempBool := CheckErr(   AEDisposeDesc(docList) , 919 );
  6468.   HandleOpenDocs := myErr;
  6469.   PostHandler(reply,myErr);
  6470. END;    { HandleOpenDocs }
  6471.  
  6472. {$S QuillNew}
  6473. FUNCTION HandlePaste(theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr;
  6474. { **NOTE: this will have to be rewritten to handle more parameters, which Paste can have }
  6475. LABEL 9;
  6476. VAR myErr:            OSErr;
  6477.     window:            WindowPtr;
  6478. BEGIN
  6479.   PreHandler;
  6480.   IF CatchErr(   SetUpEdit(theAppleEvent,window) , 18013 , myErr ) THEN GOTO 9;
  6481.   
  6482.   { got the selection, so paste; pass any errors to the client (**CHECK) }
  6483.   gTempBool := CatchErr(   MyDoPaste(window) , 18014 , myErr );
  6484.   
  6485. 9:    { finish up }
  6486.   HandlePaste := myErr;
  6487.   PostHandler(reply,myErr);
  6488. END;    { HandlePaste }
  6489.  
  6490. {$S QuillNew}
  6491. FUNCTION HandlePrint(theAppleEvent: AppleEvent; reply: AppleEvent; 
  6492.     handlerRefCon: LongInt): OSErr;
  6493. { the direct parameter can be either an object specifier (which can 
  6494.   resolve to a single token or a list of tokens) or a list of files.
  6495.   (If it's a single file, it will be coerced here to a 1-element list
  6496.   for convenience of handling).  
  6497.   
  6498.   Here's the story on interaction:  we look at the interaction mode of the event's 
  6499.   SendMode.  If it's kAECanInteract (which is what the Finder sends) or kAENeverInteract,
  6500.   we don't use the Print Dialog.  If it's kAEAlwaysInteract (which is what Quill 
  6501.   sends when the Print menu item is selected) we will try to bring up the Print
  6502.   Dialog, and fail if we can't (user interaction fails).  In the kAEAlwaysInteract
  6503.   case, even if we have a list of object tokens, we'll only bring up the Print
  6504.   Dialog ONCE, and only when we actually have something to print.
  6505.   
  6506.   In order to do that, we use two globals (of all things!), gInterMode and 
  6507.   gTriedDialog.  They are initialized here.
  6508. }
  6509. LABEL 9;
  6510. VAR myErr:        OSErr;
  6511.     dirObj:        AEDesc;
  6512.     resDesc:    AEDesc;
  6513. BEGIN
  6514.   PreHandler;
  6515.   myErr := genericErr;
  6516.   InitSomeDescs(@dirObj,@resDesc,NIL,NIL,NIL);
  6517.   
  6518.   { try to get the direct object as an obj spec }
  6519.   myErr := AEGetParamDesc(theAppleEvent,keyDirectObject,typeObjectSpecifier,dirObj);
  6520.       
  6521.   IF myErr <> noErr THEN
  6522.     BEGIN
  6523.       { failing that, a list - presumably of files }
  6524.       IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,dirObj) , 1713 ,
  6525.           myErr ) THEN GOTO 9;
  6526.     END;
  6527.     
  6528.   { check for missing params }
  6529.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 1714 , myErr ) THEN GOTO 9;
  6530.   
  6531.   { get the interact mode form the event }
  6532.   IF CatchErr(   GetInteractMode(theAppleEvent,gInterMode) , 1715 , myErr ) THEN GOTO 9;
  6533.   gTriedDialog := FALSE;    { haven't tried it so far }
  6534.     
  6535.   { if it's an object, resolve it }  
  6536.   IF dirObj.descriptorType = typeObjectSpecifier THEN
  6537.     BEGIN
  6538.       IF CatchErr(   AEResolve(dirObj,kAEIDoMinimum,resDesc) , 1716 , myErr )
  6539.           THEN GOTO 9;
  6540.           
  6541.       { it's either a single token or a list thereof }
  6542.       IF resDesc.descriptorType = typeAEList
  6543.       THEN gTempBool := CatchErr(   PrintTokenList(resDesc) , 1717 , myErr )
  6544.       ELSE gTempBool := CatchErr(   PrintToken(resDesc) , 1718 , myErr );
  6545.       
  6546.       GOTO 9;
  6547.     END;    { of typeObjectSpecifier }
  6548.     
  6549.   { if it gets here it's a list, presumably of files }
  6550.   gTempBool := CatchErr(   PrintFileList(dirObj) , 1719 , myErr );
  6551.   
  6552. 9:
  6553.   gTempBool := CheckErr(   DisposeSomeDescs(@dirObj,@resDesc,NIL,NIL,NIL) , 1720 ); 
  6554.   
  6555.   HandlePrint := myErr;
  6556.   PostHandler(reply,myErr);
  6557. END;    { HandlePrint }
  6558.  
  6559. {$S QuillNew }
  6560. FUNCTION HandleQuitApp(theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr;
  6561. { quit the program.  Pick up the interact mode and optional save parameter, for use by
  6562.   Terminate.  The save parameter can be "yes" (save all documents without asking the user),
  6563.   "no" (don't save any documents), or "ask user" (ask on each document - the default in this
  6564.   case).
  6565.   NOTES:    **CHECK on how I should let the client know that the user cancelled, a save
  6566.               failed, or whatever
  6567. }
  6568. LABEL 9;
  6569. VAR myErr:            OSErr;
  6570.     returnedType:    DescType;
  6571.     saveOpt:        DescType;
  6572.     tempErr:        OSErr;
  6573.     actSize:        Size;
  6574.     userCancelled:    BOOLEAN;
  6575. BEGIN
  6576.   PreHandler;
  6577.   myErr := errAEEventNotHandled;
  6578.   
  6579.   { pick up optional save parameter }
  6580.   saveOpt := kAEAsk;    { the default }
  6581.   
  6582.   tempErr := AEGetParamPtr(theAppleEvent,keyAESaveOptions,typeEnumerated,returnedType,
  6583.       @saveOpt,SizeOf(saveOpt),actSize);
  6584.       
  6585.   IF (tempErr <> noErr) & (tempErr <> errAEDescNotFound) THEN
  6586.     BEGIN
  6587.       { some unexpected error while trying to get param }
  6588.       gTempBool := CatchErr(   tempErr , 8215 , myErr );
  6589.       GOTO 9;    { finish up }
  6590.     END;
  6591.   
  6592.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 8213 , myErr ) THEN GOTO 9;
  6593.   
  6594.   gTempBool := CatchErr(   MyTerminate(saveOpt,userCancelled) , 8214 , myErr);
  6595.   
  6596. 9:    { set function value }
  6597.   HandleQuitApp := myErr;
  6598.   PostHandler(reply,myErr);
  6599. END;    { HandleQuitApp }
  6600.  
  6601. {$S QuillNew }
  6602. FUNCTION HandleSave(theAppleEvent: AppleEvent; reply: AppleEvent;
  6603.     handlerRefCon: LongInt): OSErr;
  6604. { pick up the direct parameter as a thing that can be saved, and 
  6605.   save it.  There may be an optional parameter specifying a file to
  6606.   save to; if there isn't, come up with the best file you can
  6607.   (we'll use GetFileAndSaveWndw for that).
  6608.   If the call succeeds, it also changes the name of the window
  6609.   to the name of the file, and marks the window doc with the 
  6610.   file spec.  These may both be redundant for a "save" command
  6611.   (but possibly not for a "save as")
  6612.   The routine doesn't interact with the user; that's done
  6613.   "up top" (before the AppleEvent is sent)
  6614. }
  6615. LABEL 9;
  6616. VAR returnedType:    DescType;
  6617.     window:            WindowPtr;
  6618.     actSize:        Size;
  6619.     myErr:            OSErr;
  6620.     tempErr:        OSErr;
  6621.     gotFileParam:    BOOLEAN;
  6622.     myFSSpec:        FSSpec;
  6623. BEGIN
  6624.   PreHandler;
  6625.   myErr := errAEEventNotHandled;
  6626.   
  6627.   { pick up the direct object as a window, the only thing I know how to save right now }
  6628.   IF CatchErr(   AEGetParamPtr(theAppleEvent,keyDirectObject,typeMyWndw,returnedType,
  6629.       @window,SizeOf(window),actSize) , 7213 , myErr ) THEN GOTO 9;    { finish up }
  6630.       
  6631.   { pick up optional file param, if any }
  6632.   tempErr := AEGetParamPtr(theAppleEvent,keyAEDestination,typeFSS,returnedType,
  6633.       @myFSSpec,SizeOf(myFSSpec),actSize);
  6634.           
  6635.   IF (tempErr <> noErr) & (tempErr <> errAEDescNotFound) THEN
  6636.     BEGIN
  6637.       { unexpected error while trying to get optional param }
  6638.       gTempBool := CatchErr(   tempErr , 7214 , myErr );
  6639.       GOTO 9;
  6640.     END;
  6641.     
  6642.   gotFileParam := (tempErr = noErr);
  6643.   
  6644.   { check to make sure we got all required parameters }
  6645.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 7215 , myErr ) THEN GOTO 9;
  6646.   
  6647.   { now save }
  6648.   gTempBool := CatchErr(   GetFileAndSaveWndw(window,gotFileParam,myFSSpec) , 7216 , myErr );
  6649.   
  6650.   { and set window title and docFile }
  6651.   SetWTitle(window,myFSSpec.name);
  6652.   DocumentPeek(window)^.docFile := myFSSpec;
  6653.  
  6654. 9:    { set function result }
  6655.   HandleSave := myErr;
  6656.   PostHandler(reply,myErr);
  6657. END;    { HandleSave }
  6658.  
  6659. {$S QuillNew}
  6660. FUNCTION HandleSetData(theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr;
  6661. { 09/17/91    BHM        rewritten to handle lists better
  6662. }
  6663. LABEL 9;
  6664. VAR myErr:        OSErr;
  6665.     myDirObj:    AEDesc;
  6666.     myDataDesc:    AEDesc;
  6667.     newDesc:    AEDesc;
  6668. BEGIN
  6669.   PreHandler;
  6670.   myErr := errAEEventNotHandled;
  6671.   InitSomeDescs(@myDirObj,@myDataDesc,@newDesc,NIL,NIL);
  6672.   
  6673.   { pick up the direct object, which is the object whose data is to be set }
  6674.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyDirectObject,typeWildCard,myDirObj) , 
  6675.       15013 , myErr ) THEN GOTO 9;    { finish up }
  6676.       
  6677.   { now the data to set it to }
  6678.   IF CatchErr(   AEGetParamDesc(theAppleEvent,keyAEData,typeWildCard,myDataDesc) , 15014 ,
  6679.       myErr ) THEN GOTO 9;
  6680.  
  6681.   { missing any parameters? }
  6682.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 15015 , myErr ) THEN GOTO 9;
  6683.   
  6684.   { the direct parameter must be an object - resolve it }
  6685.   IF CatchErr(   AEResolve(myDirObj,kAEIDoMinimum,newDesc) , 15017 , myErr ) THEN GOTO 9;
  6686.   
  6687.   { now it's either a token or a "token list" }
  6688.   IF newDesc.descriptorType = typeAEList
  6689.   THEN gTempBool := CatchErr(   SetDataForTokenList(newDesc,myDataDesc) , 15018 , myErr )
  6690.   ELSE gTempBool := CatchErr(   SetDataForToken(newDesc,myDataDesc) , 15019 , myErr );
  6691.   
  6692. 9:    { finish up }
  6693.   gTempBool := CheckErr(   DisposeSomeDescs(@myDirObj,@myDataDesc,@newDesc,NIL,NIL) , 15020 );
  6694.   
  6695.   HandleSetData := myErr;
  6696.   PostHandler(reply,myErr);
  6697. END;    { HandleSetData }
  6698.  
  6699.  
  6700. {$S QuillNew }
  6701. FUNCTION IndexFromWndwPtr(window: WindowPtr): INTEGER;
  6702. { given a winodw ptr, find its position in the
  6703.   front-to-back ordering.  If it isn't even a current
  6704.   window, return 0.
  6705.   INPUTS:    window        ptr to the window record
  6706.   OUTPUTS:    window index (0 if it's not even a window)
  6707.   ERRORS:
  6708.   SIDE EFFECTS:
  6709. }
  6710. VAR i:          INTEGER;
  6711.     thisWindow:    WindowPtr;
  6712. BEGIN
  6713.   IndexFromWndwPtr := 0;
  6714.   i := 0;
  6715.   thisWindow := FrontWindow;
  6716.   WHILE thisWindow <> NIL DO
  6717.     BEGIN
  6718.       i := i+1;
  6719.       IF thisWindow = window THEN
  6720.         BEGIN    { found it }
  6721.           IndexFromWndwPtr := i;
  6722.           EXIT(IndexFromWndwPtr);
  6723.         END;
  6724.       { didn't find it - try next window }
  6725.       thisWindow := WindowPtr(WindowPeek(thisWindow)^.nextWindow);
  6726.     END;
  6727. END; { IndexFromWndwPtr }
  6728.  
  6729. {$S Initialize}
  6730. PROCEDURE InitAEHandlers;
  6731. VAR myErr:    OSErr;
  6732. BEGIN
  6733.   gTempBool := CheckErr(   AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,@HandleQuitApp,0,FALSE) , 1013 );
  6734.   gTempBool := CheckErr(   AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,@HandleOpenDocs,0,FALSE) , 1014 );
  6735.   gTempBool := CheckErr(   AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,@HandleOpenApp,0,FALSE) , 1015 );
  6736.   gTempBool := CheckErr(   AEInstallEventHandler(kCoreEventClass,kAEPrint,@HandlePrint,0,FALSE) , 1016 );
  6737.  
  6738.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAEClose,@HandleClose,0,FALSE) , 1017 );
  6739.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAESave,@HandleSave,0,FALSE) , 1018 );
  6740.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAEGetData,@HandleGetData,0,FALSE) , 1020 );
  6741.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAESetData,@HandleSetData,0,FALSE) , 1021 );
  6742.   gTempBool := CheckErr(   AEInstallEventHandler(kAEMiscStandards,kAECut,@HandleCut,0,FALSE) , 1022 );
  6743.   gTempBool := CheckErr(   AEInstallEventHandler(kAEMiscStandards,kAECopy,@HandleCopy,0,FALSE) , 1023 );
  6744.   gTempBool := CheckErr(   AEInstallEventHandler(kAEMiscStandards,kAEPaste,@HandlePaste,0,FALSE) , 1024 );
  6745.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAECountElements,@HandleCountElements,0,FALSE) , 1025 );
  6746.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAEMove,@HandleMove,0,FALSE) , 1026 );
  6747.     
  6748.   { object stuff }
  6749.   gTempBool := CheckErr(   AEObjectInit , 1027 );
  6750.   gTempBool := CheckErr(   AESetObjectCallbacks(@MyCompareProc,@MyCountProc,NIL,NIL,NIL,NIL,@MyGetErrorDesc) , 1028 );
  6751.   gTempBool := CheckErr(   AEInstallObjectAccessor(cWindow,typeNull,@WndwFromNullAccessor,0,FALSE) , 1029 );
  6752.   gTempBool := CheckErr(   AEInstallObjectAccessor(cDocument,typeNull,@WndwFromNullAccessor,0,FALSE) , 1029 );
  6753.   gTempBool := CheckErr(   AEInstallObjectAccessor(cWord,typeMyWndw,@TextElemFromWndwAccessor,0,FALSE) , 1030 );
  6754.   gTempBool := CheckErr(   AEInstallObjectAccessor(cChar,typeMyWndw,@TextElemFromWndwAccessor,0,FALSE) , 1031 );
  6755.   gTempBool := CheckErr(   AEInstallObjectAccessor(cChar,typeMyWndw,@TextElemFromWndwAccessor,0,FALSE) , 1032 );
  6756.   gTempBool := CheckErr(   AEInstallObjectAccessor(cSpot,typeMyWndw,@TextElemFromWndwAccessor,0,FALSE) , 1033 );
  6757.   gTempBool := CheckErr(   AEInstallObjectAccessor(cLine,typeMyWndw,@TextElemFromWndwAccessor,0,FALSE) , 1034 );
  6758.   gTempBool := CheckErr(   AEInstallObjectAccessor(cItem,typeMyWndw,@TextElemFromWndwAccessor,0,FALSE) , 1035 );
  6759.   
  6760.   gTempBool := CheckErr(   AEInstallObjectAccessor(cWord,typeMyDoc,@TextElemFromWndwAccessor,0,FALSE) , 1030 );
  6761.   gTempBool := CheckErr(   AEInstallObjectAccessor(cChar,typeMyDoc,@TextElemFromWndwAccessor,0,FALSE) , 1031 );
  6762.   gTempBool := CheckErr(   AEInstallObjectAccessor(cChar,typeMyDoc,@TextElemFromWndwAccessor,0,FALSE) , 1032 );
  6763.   gTempBool := CheckErr(   AEInstallObjectAccessor(cSpot,typeMyDoc,@TextElemFromWndwAccessor,0,FALSE) , 1033 );
  6764.   gTempBool := CheckErr(   AEInstallObjectAccessor(cLine,typeMyDoc,@TextElemFromWndwAccessor,0,FALSE) , 1034 );
  6765.   gTempBool := CheckErr(   AEInstallObjectAccessor(cItem,typeMyDoc,@TextElemFromWndwAccessor,0,FALSE) , 1035 );
  6766.   
  6767.   gTempBool := CheckErr(   AEInstallObjectAccessor(cChar,typeMyText,@TextElemFromTextAccessor,0,FALSE) , 1036 );
  6768.   gTempBool := CheckErr(   AEInstallObjectAccessor(cSpot,typeMyText,@TextElemFromTextAccessor,0,FALSE) , 1037 );
  6769.   gTempBool := CheckErr(   AEInstallObjectAccessor(cWord,typeMyText,@TextElemFromTextAccessor,0,FALSE) , 1038 );
  6770.   gTempBool := CheckErr(   AEInstallObjectAccessor(cLine,typeMyText,@TextElemFromTextAccessor,0,FALSE) , 1039 );
  6771.   gTempBool := CheckErr(   AEInstallObjectAccessor(cItem,typeMyText,@TextElemFromTextAccessor,0,FALSE) , 1040 );
  6772.   gTempBool := CheckErr(   AEInstallObjectAccessor(cProperty,typeMyWndw,@PropFromWndwAccessor,0,FALSE) , 1041 );
  6773.   gTempBool := CheckErr(   AEInstallObjectAccessor(cProperty,typeMyDoc,@PropFromWndwAccessor,0,FALSE) , 1041 );
  6774.   gTempBool := CheckErr(   AEInstallObjectAccessor(cProperty,typeMyText,@PropFromTextAccessor,0,FALSE) , 1042 );
  6775.   gTempBool := CheckErr(   AEInstallObjectAccessor(cProperty,typeNull,@PropFromAppAccessor,0,FALSE) , 1043 );
  6776.   gTempBool := CheckErr(   AEInstallObjectAccessor(cListElem,typeWildCard,@ElemFromAnythingAccessor,0,FALSE) , 1044 );
  6777.   gTempBool := CheckErr(   AEInstallObjectAccessor(typeWildCard,typeAEList,@AnythingFromListAccessor,0,FALSE) , 1045 );
  6778.   
  6779.  
  6780.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeMyWndw,@CoerceObjToAnything,0,TRUE,FALSE) , 1046 ) ;
  6781.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeMyDoc,@CoerceObjToAnything,0,TRUE,FALSE) , 1046 ) ;
  6782.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeMyText,@CoerceObjToAnything,0,TRUE,FALSE) , 1047 ) ;
  6783.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeMyWndwProp,@CoerceObjToAnything,0,TRUE,FALSE) , 1048 ) ;
  6784.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeMyTextProp,@CoerceObjToAnything,0,TRUE,FALSE) , 1049 ) ;
  6785.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeMyAppProp,@CoerceObjToAnything,0,TRUE,FALSE) , 1050 ) ;
  6786.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeStyledText,@CoerceObjToAnything,0,TRUE,FALSE) , 1051 ) ;
  6787.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeChar,@CoerceObjToAnything,0,TRUE,FALSE) , 1052 ) ;
  6788.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeAEList,@CoerceObjToAnything,0,TRUE,FALSE) , 1053 ) ;
  6789.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeObjectSpecifier,typeMyDoc,@CoerceObjToAnything,0,TRUE,FALSE) , 1054 ) ;
  6790.   
  6791.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeStyledText,typeChar,@CoerceStylTextToText,0,TRUE,FALSE) , 1055 ) ;  
  6792.   
  6793.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeMyText,typeStyledText,@CoerceMyTextToStylText,0,TRUE,FALSE) , 1056 ) ;
  6794.     
  6795.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeMyDoc,typeMyWndw,@CoerceMyDocToMyWndw,0,TRUE,FALSE) , 1065 ) ;
  6796.   
  6797.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAEDelete,@HandleDeleteElement,0,FALSE) , 1026 );
  6798.   
  6799.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeAEList,typeTextStyles,@CoerceListOrValToTextStyles,0,TRUE,FALSE) , 1066 );
  6800.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeEnumerated,typeTextStyles,@CoerceListOrValToTextStyles,0,TRUE,FALSE) , 1067 );
  6801.   
  6802.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAECreateElement,@HandleCreateElement,0,FALSE) , 1068 );
  6803.   
  6804.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeStyledText,typeIntlText,@CoerceStylTextToIntlText,0,TRUE,FALSE) , 1069 );
  6805.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeChar,typeIntlText,@CoerceTextToIntlText,0,TRUE,FALSE) , 1070 );
  6806.   gTempBool := CheckErr(   AEInstallCoercionHandler(typeIntlText,typeChar,@CoerceIntlTextToText,0,TRUE,FALSE) , 1071 );
  6807.   
  6808. { the next, commented-out routine is used when we want to monitor unfamiliar Apple Events that we receive } 
  6809. {  gTempBool := CheckErr(   AEInstallEventHandler(typeWildCard,typeWildCard,@HandleWild,0,FALSE) , 1072 );}
  6810.  
  6811.   gTempBool := CheckErr(   AEInstallEventHandler(kAECoreSuite,kAEDoObjectsExist,@HandleDoObjectsExist,0,FALSE) , 1073 );
  6812.   
  6813. END;    { InitAEHandlers }
  6814.  
  6815. {$S QuillNew2}
  6816. PROCEDURE InitKeyBuffer;
  6817. { this routine initializes the values in the key buffer and 
  6818.   creates the bufChars handle at its minimum size
  6819.   INPUTS:    none
  6820.   OUTPUTS:    none
  6821.   NOTES:    we might want to do better error handling . . .
  6822. }
  6823. BEGIN
  6824.   keyBuffer.bufChars := CharBufHandle(NewHandle(kBufStartSize));
  6825.   IF MemError <> noErr THEN
  6826.     BEGIN
  6827.       DoMyAlert('Trouble in InitKeyBuffer - out of memory!');    { a real error, should be handled better }
  6828.       EXIT(InitKeyBuffer);
  6829.     END;
  6830.   keyBuffer.bufSize := kBufStartSize;
  6831.   InitKeyBufVals;
  6832. END;    { InitKeyBuffer }
  6833.  
  6834. {$S QuillNew2}
  6835. PROCEDURE InitKeyBufVals;
  6836. { this routine intializes some of the values in the
  6837.   key buffer to their defaults.  It is called when the
  6838.   key buffer is first initialized, and after it has been
  6839.   emptied.  It does NOT size or resize the bufChars handle
  6840.   INPUTS:    none
  6841.   OUTPUTS:    none
  6842.   10/03/91    BHM        added bufDesc
  6843. }
  6844. BEGIN
  6845.   WITH keyBuffer DO
  6846.     BEGIN
  6847.       bufEmpty := TRUE;
  6848.       
  6849.       { the following values are supposed to be set by StartKeyBuffering; we'll  } 
  6850.       { give them illegal values that can be easily recognized                   }
  6851.       bufCharCount := -1;
  6852.       bufDelCount := -1;
  6853.       bufSelStart := -1;
  6854.       bufSelEnd := -1;
  6855.       
  6856.       bufWndw := NIL;
  6857.       
  6858.       bufDesc := gNullDesc;
  6859.     END;
  6860. END;    { InitKeyBufVals }
  6861.  
  6862.  
  6863.  
  6864. {$S QuillNew }
  6865. PROCEDURE InitSomeDescs(desc1Ptr, desc2Ptr, desc3Ptr, desc4Ptr, desc5Ptr: DescPtr);
  6866. { set a bunch of descriptors to the null descriptor.  The inputs are pointers to
  6867.   the descriptors.  If one or more of the pointers is NIL, then the routine ignores
  6868.   all the inputs after that one (they should be NIL, too).  So, for example, if
  6869.   desc3Ptr is NIL, only the descriptors pointed to by desc1Ptr and desc2Ptr are
  6870.   initialized.
  6871.   INPUTS:    as above
  6872.   OUTPUTS:    none
  6873.   NOTES:    (1) **WARNING** if any of the inputs is NIL, it and all the subsequent
  6874.               inputs are ignored
  6875.             (2) Because 5 seemed like a nice number, that's why!
  6876. }
  6877. BEGIN
  6878.   IF desc1Ptr = NIL THEN EXIT(InitSomeDescs);
  6879.   desc1Ptr^ := gNullDesc;
  6880.   IF desc2Ptr = NIL THEN EXIT(InitSomeDescs);
  6881.   desc2Ptr^ := gNullDesc;
  6882.   IF desc3Ptr = NIL THEN EXIT(InitSomeDescs);
  6883.   desc3Ptr^ := gNullDesc;
  6884.   IF desc4Ptr = NIL THEN EXIT(InitSomeDescs);
  6885.   desc4Ptr^ := gNullDesc;
  6886.   IF desc5Ptr = NIL THEN EXIT(InitSomeDescs);
  6887.   desc5Ptr^ := gNullDesc;
  6888. END;  { InitSomeDescs }
  6889.  
  6890. {$S QuillNew}
  6891. PROCEDURE InitTextToken(VAR myText: TextToken);
  6892. { initialize a text token to some easily 
  6893.  recognizable (and usually illegal) values 
  6894.  INPUTS:    myText        VAR token to be initialized
  6895.  OUTPUTS:    none
  6896. }
  6897. BEGIN
  6898.   WITH myText DO
  6899.     BEGIN
  6900.       tokenClass := cNull;
  6901.       tokenWndw := NIL;
  6902.       tokenOffset := -1;
  6903.       tokenLength := -1;
  6904.     END;
  6905. END;    { InitTextToken }
  6906.  
  6907. {$S QuillNew}
  6908. PROCEDURE InitTheStyles;
  6909. { this routine sets up a global data structure, theStyles, which is useful
  6910.   when dealing with text styles
  6911.   INPUTS:    none
  6912.   OUTPUTS:    none
  6913. }
  6914. BEGIN
  6915.   theStyles[1].stylItem := bold;
  6916.   theStyles[2].stylItem := italic;
  6917.   theStyles[3].stylItem := underline;
  6918.   theStyles[4].stylItem := outline;
  6919.   theStyles[5].stylItem := shadow;
  6920.   theStyles[6].stylItem := condense;
  6921.   theStyles[7].stylItem := extend;
  6922.  
  6923.   
  6924.   theStyles[1].stylConst := kAEBold;
  6925.   theStyles[2].stylConst := kAEItalic;
  6926.   theStyles[3].stylConst := kAEUnderline;
  6927.   theStyles[4].stylConst := kAEOutline;
  6928.   theStyles[5].stylConst := kAEShadow;
  6929.   theStyles[6].stylConst := kAECondensed;
  6930.   theStyles[7].stylConst := kAEExpanded;
  6931.   
  6932.   gAllStyles := [bold,italic,underline,outline,shadow,condense,extend];
  6933. END;    { InitTheStyles }
  6934.  
  6935. {$S QuillNew2}
  6936. FUNCTION IntlTextToText(intlTextDesc: AEDesc; VAR textDesc: AEDesc;
  6937.     VAR scrptCode: ScriptCode; VAR lngCode: LangCode): OSErr;
  6938. { another boring subroutine.  Given a descriptor of typeIntlText,
  6939.   return a desc containing just the text (typeChar); also return
  6940.   the script code and language code.
  6941.   INPUTS:    intlTextDesc        descriptor of typeIntlText
  6942.               textDesc            return VAR for the typeChar descriptor
  6943.               scrptCode            return VAR for the script code
  6944.             lngCode                return VAR for the language code
  6945.   OUTPUTS:    error code (noErr if none)
  6946.   NOTES:    even if we return an error because we couldn't create the
  6947.               text desc (due to memory problems), scrptCode and lngCode
  6948.             will still be valid
  6949. }
  6950. VAR myErr:        OSErr;
  6951.     myPtr:        Ptr;
  6952.     textLen:    LongInt;
  6953. BEGIN
  6954.   WITH intlTextDesc DO
  6955.     BEGIN
  6956.       HLock(dataHandle);
  6957.       myPtr := dataHandle^;
  6958.       scrptCode := IntegerPtr(myPtr)^;
  6959.       
  6960.       myPtr := Ptr(ORD(myPtr) + 2);
  6961.       lngCode := IntegerPtr(myPtr)^;
  6962.       
  6963.       myPtr := Ptr(ORD(myPtr) + 2);
  6964.       textLen := GetHandleSize(dataHandle) - 4;
  6965.       gTempBool := CatchErr(   AECreateDesc(typeChar,myPtr,textLen,textDesc) , 23613 , 
  6966.           myErr );
  6967.       HUnlock(dataHandle);
  6968.     END;    { of WITH intlTextDesc }
  6969.     
  6970.   IntlTextToText := myErr;
  6971. END;    { IntlTextToText}
  6972.  
  6973.  
  6974. {$S QuillNew2}
  6975. FUNCTION ListToStyleSet(stylList: AEDesc; VAR styleSet: Style; VAR plainFlag: BOOLEAN;
  6976.     checkStyles: BOOLEAN): OSErr;
  6977. { this routine takes an AEList - presumably of style items, including possibly kAEPlain - 
  6978.   and returns a corresponding style set (of QD type Style).  IF kAEPlain appears in the 
  6979.   list, then plainFlag is returned TRUE.  kAEPlain is ignored in constructing the style set.
  6980.   There is also some optional error-checking:  if checkStyles is TRUE, then the routine
  6981.   aborts if it finds a "bad" item in the list (i.e., not a style item or kAEPlain).  If
  6982.   checkStyles is FALSE, then the routine ignores bad items altogether.
  6983.   INPUTS:    stylList        the list of style items
  6984.               styleSet        return VAR for style set
  6985.             plainFlag        return VAR - TRUE if kAEPlain is in list, FALSE o.w.
  6986.             checkStyles        if TRUE, abort on bad item; if FALSE, ignore bad
  6987.                             items
  6988.   OUTPUTS:    error code (noErr if none)
  6989. }
  6990. LABEL 9;
  6991. VAR myErr:            OSErr;
  6992.     itemCount:        LongInt;
  6993.     i:                LongInt;
  6994.     badItem:        BOOLEAN;
  6995.     myItem:            DescType;
  6996.     stylItem:        StyleItem;
  6997.     tempPlainFlag:    BOOLEAN;
  6998.     tErr:            OSErr;
  6999.     uErr:            OSErr;
  7000.     junk:            LongInt;
  7001. BEGIN
  7002.   myErr := genericErr;
  7003.   styleSet := [];
  7004.   plainFlag := FALSE;
  7005.   
  7006.   { count the items }
  7007.   IF CatchErr(   AECountItems(stylList,itemCount) , 22313 , myErr ) THEN GOTO 9;
  7008.   
  7009.   IF itemCount = 0 THEN GOTO 9;    { no styles at all }
  7010.   
  7011.   FOR i := 1 TO itemCount DO
  7012.     BEGIN
  7013.       { get the item }
  7014.       badItem := (AEGetNthPtr(stylList,i,typeEnumerated,gReturnedKeywd,gReturnedType,
  7015.                       @myItem,SizeOf(myItem),gActSize) <> noErr);
  7016.  
  7017.       IF NOT badItem THEN
  7018.         BEGIN
  7019.           { got an item of typeEnumerated from the list }
  7020.           badItem := NOT GetStyleItemFromConst(myItem,stylItem,tempPlainFlag);
  7021.  
  7022.           IF NOT badItem THEN
  7023.             BEGIN
  7024.               { got style item (possibly kAEPlain) }
  7025.               IF tempPlainFlag THEN plainFlag := TRUE    { plainFlag is set to TRUE if ANY item is kAEPlain }
  7026.               ELSE styleSet := styleSet + [stylItem];    { got a real style item }
  7027.             END;    { of: got a style item (possibly kAEPlain) }
  7028.         
  7029.         END;    { of: got a typeEnumerated }
  7030.         
  7031.       { now check for trouble, if you're supposed to }
  7032.       IF checkStyles & badItem THEN
  7033.         BEGIN
  7034.           gTempBool := CatchErr(   errAEBadData , 22314 , myErr );
  7035.           GOTO 9;    { abort loop }
  7036.         END;
  7037.         
  7038.     END;    { of loop }
  7039.     
  7040. 9:
  7041.   IF myErr <> noErr THEN
  7042.     BEGIN
  7043.       { just for neatness }
  7044.       styleSet := [];
  7045.       plainFlag := FALSE;
  7046.     END;
  7047.     
  7048.   ListToStyleSet := myErr;
  7049. END;    { ListToStyleSet }
  7050.  
  7051.  
  7052. {$S QuillNew2}
  7053. FUNCTION MakeElemList(elemClass: DescType; srcText: TextToken;
  7054.     VAR elemList: AEDesc): OSErr;
  7055. { given a class of text element (word, item, etc.) and some text,
  7056.   make a list of all the elements of that class in the text
  7057.   INPUTS:    elemClass        class of the text element
  7058.               srcText            text token for the text
  7059.             elemList        return VAR for the resulting list
  7060.   OUTPUTS:    error code (noErr if none)
  7061.   NOTES:    (1) this implementation is inefficient, since for each
  7062.               item it starts counting from the beginning of the
  7063.             text again; we can speed it up if we want to get clever
  7064.             (2) we might want a "count" input parameter; most calling
  7065.             routines have already done the count before this
  7066.             (3) we don't validate elemClass here because a bad value
  7067.             will be picked up by the call to CountTextElems
  7068. }
  7069. LABEL 9;
  7070. VAR myErr:        OSErr;
  7071.     elemCount:    LongInt;
  7072.     i:            LongInt;
  7073.     elemText:    TextToken;
  7074. BEGIN
  7075.   myErr := genericErr;
  7076.   
  7077.   { make the empty list }
  7078.   IF CatchErr(   AECreateList(NIL,0,FALSE,elemList) , 20713 , myErr ) THEN GOTO 9;
  7079.   
  7080.   { count the text elems }
  7081.   IF CatchErr(   CountTextElems(srcText,elemClass,elemCount) , 20714 , myErr )
  7082.       THEN GOTO 9;
  7083.       
  7084.   IF elemCount = 0 THEN GOTO 9;    { empty list }
  7085.   
  7086.   { step through the elems }
  7087.   FOR i := 1 TO elemCount DO
  7088.     BEGIN
  7089.       { get a token for the item }
  7090.       IF CatchErr(   GetTextElemFromText(srcText,elemClass,i,elemText) , 20715 ,
  7091.           myErr ) THEN GOTO 9;
  7092.           
  7093.       { put it in the list }
  7094.       IF CatchErr(   AEPutPtr(elemList,0,typeMyText,@elemText,SizeOf(elemText)) , 
  7095.           20716 , myErr ) THEN GOTO 9;
  7096.     END;
  7097.     
  7098. 9:
  7099.   { since there are possible errors AFTER the list is created, we will, in the }
  7100.   { error case, want to dispose of the list                                    }
  7101.   
  7102.   IF myErr <> noErr THEN gtempBool := CheckErr(   AEDisposeDesc(elemList) , 20717 );
  7103.   
  7104.   MakeElemList := myErr;
  7105. END;    { MakeElemList }
  7106.  
  7107. {$S QuillNew2}
  7108. FUNCTION MakeInsertionLoc(relObj: AEDesc; position: DescType;
  7109.     VAR insertionLoc: AEDesc): OSErr;
  7110. { this routine takes an object and a position, corresponding to
  7111.   the two fields of an insertion loc, and creates the insertion
  7112.   loc.
  7113.   INPUTS:    relObj            the "object" field for the insertion loc
  7114.                               (should be typeObjectSpecifier or typeNull)
  7115.             position        the "position" field (should be kAEBefore,
  7116.                             kAEAfter, kAEReplace, kAEBeginning, or kAEEnd)
  7117.             theInsLoc        return VAR for the insertion loc (a descriptor 
  7118.                             of typeInsertionLoc
  7119.   OUTPUTS:    error code (noErr if none)
  7120.   NOTES:    (1) currently we do not validate the inputs
  7121.               (2) we use the name "relObj" because the insertion loc is defined
  7122.             relative to that object
  7123. }
  7124. LABEL 9;
  7125. VAR myErr:        OSErr;
  7126.     insLocRec:    AEDesc;
  7127. BEGIN
  7128.   myErr := genericErr;
  7129.   InitSomeDescs(@insertionLoc,@insLocRec,NIL,NIL,NIL);
  7130.   
  7131.   { create AERecord }
  7132.   IF CatchErr(   AECreateList(NIL,0,TRUE,insLocRec) , 23413 , myErr ) THEN GOTO 9;
  7133.   
  7134.   { add "object" field }
  7135.   IF CatchErr(   AEPutKeyDesc(insLocRec,keyAEObject,relObj) , 23414 , myErr )
  7136.       THEN GOTO 9;
  7137.       
  7138.   { add "position" field }
  7139.   IF CatchErr(   AEPutKeyPtr(insLocRec,keyAEPosition,typeEnumerated,@position,
  7140.       SizeOf(position)) , 23415 , myErr ) THEN GOTO 9;
  7141.       
  7142.   { now coerce to typeInsertionLoc }
  7143.   gTempBool := CatchErr(   AECoerceDesc(insLocRec,typeInsertionLoc,insertionLoc) , 23416 , 
  7144.       myErr);
  7145.       
  7146. 9:
  7147.   { no need to dispose insertionLoc, even in error case, because creating it is the last thing we do }
  7148.   
  7149.   gTempBool := CatchErr(   AEDisposeDesc(insLocRec) , 23417 , myErr );
  7150.   
  7151.   MakeInsertionLoc := myErr;
  7152. END;    { MakeInsertionLoc }
  7153.  
  7154. {$S QuillNew }
  7155. FUNCTION MakeObjSpec(desiredClass: DescType; theCont: AEDesc; keyForm: DescType;
  7156.     keyDataType: DescType; keyDataPtr: Ptr; keyDataSize: Size; VAR result: AEDesc):  OSErr;
  7157. { makes a descriptor of typeObjectSpecifier out of 4 things: desired class, 
  7158.   containing object, key form, and key data.  The methods of specifying
  7159.   the 4 things (simple inputs for class and key form, AEDesc for container,
  7160.   type, ptr, and size for key data) may seem oddly mixed, but this is the 
  7161.   form we most often need it.
  7162.   INPUTS:    desiredClass        class of the object
  7163.               theCont                container for the object
  7164.             keyForm                key form for the object
  7165.             keyDataType            type for key data
  7166.             keyDataPtr            ptr to key data
  7167.             keyDataSize            size of key data
  7168.             result                destination VAR for resulting object specifier
  7169.   OUTPUTS:    error code (noErr if none)
  7170.   ERRORS:
  7171.   SIDE EFFECTS:
  7172.   NOTES:    if MakeObj returns noErr, then result is a valid descriptor that
  7173.               the caller is responsible for disposing.  If an error code is returned,
  7174.             result is undefined and doesn't have to be disposed.
  7175. }
  7176. LABEL 8,9;
  7177. VAR myObjSpecRec:    AERecord;
  7178.     myErr:            OSErr;
  7179. BEGIN
  7180.   { create an object specifier record, which is an AERecord }
  7181.   
  7182.   { start by creating empty record list}
  7183.   IF CatchErr(   AECreateList(NIL,0,TRUE,myObjSpecRec) , 3613 , myErr )
  7184.       THEN GOTO 9;    { must set function result }
  7185.       
  7186.   { add desired class }
  7187.   IF CatchErr(   AEPutKeyPtr(myObjSpecRec,keyAEDesiredClass,typeType,@desiredClass,SizeOf(desiredClass)) , 
  7188.       3614 , myErr ) THEN GOTO 8;    { must dispose of obj spec rec }
  7189.       
  7190.   { add container }
  7191.   IF CatchErr(   AEPutKeyDesc(myObjSpecRec,keyAEContainer,theCont) , 3615 , myErr )
  7192.       THEN GOTO 8;
  7193.       
  7194.   { add key form }
  7195.   IF CatchErr(   AEPutKeyPtr(myObjSpecRec,keyAEKeyForm,typeEnumerated,@keyForm,SizeOf(keyForm)) , 
  7196.       3616 , myErr ) THEN GOTO 8;
  7197.       
  7198.   { add key data }
  7199.   IF CatchErr(   AEPutKeyPtr(myObjSpecRec,keyAEKeyData,keyDataType,keyDataPtr,keyDataSize) , 
  7200.       3617 , myErr ) THEN GOTO 8;
  7201.       
  7202.   { now coerce the AERecord to an object specifier }
  7203.   IF CatchErr(   AECoerceDesc(myObjSpecRec,typeObjectSpecifier,result) , 3618 , myErr )
  7204.       THEN GOTO 8;
  7205.       
  7206.   { looks good to me }
  7207.   myErr := noErr;
  7208.   
  7209. 8:    { dispose of obj spec rec }
  7210.   gTempLong := AEDisposeDesc(myObjSpecRec);
  7211.   
  7212. 9:    { set function result }
  7213.   MakeObjSpec := myErr;
  7214. END;    { MakeObjSpec }    
  7215.  
  7216. {$S QuillNew }
  7217. FUNCTION MakeObjSpecFromIndex(desiredClass: DescType; theCont: AEDesc;
  7218.     index: LongInt; VAR result: AEDesc): OSErr;
  7219. { make a descriptor (of typeObjectSpecifier) for an object,
  7220.   given its desired class class and an index within a container.
  7221.   INPUTS:    desiredClass        class of the resulting object
  7222.               theCont                container for the object
  7223.             index                the index of the object
  7224.             result                destination VAR for resulting object specifier
  7225.   OUTPUTS:    error code (noErr if none)
  7226.   ERRORS:
  7227.   SIDE EFFECTS:
  7228.   NOTES:    (1) if MakeObjSpecFromIndex returns noErr, then result is a valid
  7229.               descriptor that the caller is responsible for disposing.  If an
  7230.             error code is returned, result is undefined and doesn't have to
  7231.             be disposed.
  7232.             (2) This is basically a cover proc for MakeObjSpec, which, because of its generality,
  7233.             has more inputs than anyone should have to look at very often.
  7234. }
  7235. BEGIN
  7236.   MakeObjSpecFromIndex := MakeObjSpec(desiredClass,theCont,formAbsolutePosition,
  7237.       typeLongInteger,@index,SizeOf(index),result);
  7238. END;    { MakeObjSpecFromIndex }
  7239.  
  7240. {$S QuillNew }
  7241. FUNCTION MakeObjSpecFromName(desiredClass: DescType; theCont: AEDesc;
  7242.     name: Str255; VAR result: AEDesc): OSErr;
  7243. { make a descriptor (of typeObjectSpecifier) for an object,
  7244.   given its desired class, a name, and a container.
  7245.   INPUTS:    desiredClass        class of the resulting object
  7246.               theCont                container for the object
  7247.             name                the name of the object
  7248.             result                destination VAR for resulting object specifier
  7249.   OUTPUTS:    error code (noErr if none)
  7250.   ERRORS:
  7251.   SIDE EFFECTS:
  7252.   NOTES:    (1) if MakeObjSpecFromName returns noErr, then result is a valid
  7253.               descriptor that the caller is responsible for disposing.  If an
  7254.             error code is returned, result is undefined and doesn't have to
  7255.             be disposed.
  7256. }
  7257. VAR namePtr:    Ptr;
  7258.     nameLen:    LongInt;
  7259. BEGIN
  7260.   namePtr := Ptr(ORD4(@name)+1);
  7261.   nameLen := length(name);
  7262.   MakeObjSpecFromName := MakeObjSpec(desiredClass,theCont,formName,
  7263.       typeChar,namePtr,nameLen,result);
  7264. END;    { MakeObjSpecFromName }
  7265.  
  7266. {$S QuillNew}
  7267. FUNCTION MakeObjSpecFromRange(desiredClass: DescType; theCont: AEDesc; startObj: AEDesc;
  7268.     stopObj: AEDesc; VAR result: AEDesc): OSErr;
  7269. { make a descriptor of typeObjectSpecifier representing a range of things within
  7270.   a container.
  7271.   INPUTS:    desiredClass        class of the things in the range
  7272.               theCont                object containing the range
  7273.             startObj            starting boundary of the range
  7274.             stopObj                ending boundary of the range
  7275.             result                return VAR for resulting obj desc
  7276.   OUTPUTS:    error code (noErr if none)
  7277. }
  7278. LABEL 9;
  7279. VAR myErr:            OSErr;
  7280.     rdRec:            AERecord;
  7281.     rdDesc:            AEDesc;
  7282.     keyForm:        DescType;
  7283.     myObjSpecRec:    AEDesc;
  7284. BEGIN
  7285.   myErr := genericErr;
  7286.   InitSomeDescs(@result,@rdRec,@rdDesc,NIL,NIL);
  7287.   
  7288.   { make the range data record }
  7289.   IF CatchErr(   AECreateList(NIL,0,TRUE,rdRec) , 13913 , myErr ) THEN GOTO 9;
  7290.   
  7291.   { attach the boundary objects }
  7292.   IF CatchErr(   AEPutKeyDesc(rdRec,keyAERangeStart,startObj) , 13914 , myErr ) THEN GOTO 9;
  7293.   IF CatchErr(   AEPutKeyDesc(rdRec,keyAERangeStop,stopObj) , 13915 , myErr ) THEN GOTO 9;
  7294.   
  7295.   { coerce the record to a range data descriptor }
  7296.   IF CatchErr(   AECoerceDesc(rdRec,typeRangeDescriptor,rdDesc) , 13916 , myErr ) THEN GOTO 9;    { is that right? }
  7297.   
  7298.   { create empty record }
  7299.   IF CatchErr(   AECreateList(NIL,0,TRUE,myObjSpecRec) , 13917 , myErr ) THEN GOTO 9;
  7300.   
  7301.   { add desired class }
  7302.   IF CatchErr(   AEPutKeyPtr(myObjSpecRec,keyAEDesiredClass,typeType,@desiredClass,SizeOf(desiredClass)) , 
  7303.       13918 , myErr ) THEN GOTO 9;
  7304.       
  7305.   { add container }
  7306.   IF CatchErr(   AEPutKeyDesc(myObjSpecRec,keyAEContainer,theCont) , 13919 , myErr )
  7307.       THEN GOTO 9;
  7308.       
  7309.   { add key form }
  7310.   keyForm := formRange;
  7311.   IF CatchErr(   AEPutKeyPtr(myObjSpecRec,keyAEKeyForm,typeEnumerated,@keyForm,SizeOf(keyForm)) , 
  7312.       13920 , myErr ) THEN GOTO 9;
  7313.       
  7314.   { add key data }
  7315.   IF CatchErr(   AEPutKeyDesc(myObjSpecRec,keyAEKeyData,rdDesc) , 13921 , myErr ) THEN GOTO 9;
  7316.       
  7317.   { now coerce the AERecord to an object specifier }
  7318.   IF CatchErr(   AECoerceDesc(myObjSpecRec,typeObjectSpecifier,result) , 13922 , myErr )
  7319.       THEN GOTO 9;
  7320.       
  7321.   { note that creating result is the last thing we [try] to do, so even in an }
  7322.   { error case there's no need to dispose it  }
  7323.       
  7324. 9:    { finish up }
  7325.   gTempBool := CheckErr(   DisposeSomeDescs(@rdRec,@rdDesc,NIL,NIL,NIL) , 13923);
  7326.   
  7327.   MakeObjSpecFromRange := myErr;
  7328. END;    { MakeObjSpecFromRange }
  7329.  
  7330. {$S QuillNew2}
  7331. FUNCTION MakePlainList(VAR plainList: AEdesc): OSErr;
  7332. { this is a very silly routine used in a hack to make
  7333.   recording of "set style to plain" look a little
  7334.   nicer.  It creates an AE list containing one item, 
  7335.   the constant kAEPlain.  MakePlainList will almost
  7336.   certainly go away after we clean up some of the 
  7337.   text style stuff
  7338.   INPUTS:    plainList        return VAR for the 1-element list
  7339.   OUTPUTS:    error code (noErr if none)
  7340. }
  7341. LABEL 9;
  7342. VAR myErr:    OSErr;
  7343.     plain:    DescType;
  7344. BEGIN
  7345.   myErr := genericErr;
  7346.   
  7347.   { create list }
  7348.   IF CatchErr(   AECreateList(NIL,0,FALSE,plainList) , 19613 , myErr ) THEN GOTO 9;    { finish up }
  7349.   
  7350.   { add single item to list }
  7351.   plain := kAEPlain;
  7352.   IF CatchErr(   AEPutPtr(plainList,0,typeEnumerated,@plain,SizeOf(plain)) , 19614 , myErr )
  7353.       THEN GOTO 9;
  7354.       
  7355. 9:    { finish up }
  7356.   IF myErr <> noErr THEN gTempBool := CheckErr(   AEDisposeDesc(plainList) , 19615 );
  7357.   
  7358.   MakePlainList := myErr;
  7359. END;    { MakePlainList }
  7360.  
  7361.  
  7362. {$S QuillNew }
  7363. FUNCTION MakePropObjSpec(theObj: AEDesc; theProp: DescType;
  7364.     VAR result: AEDesc): OSErr;
  7365. { this creates a descriptor of typeObjectSpecifier that respresents 
  7366.   a particular property of a particular object - as used as parameters
  7367.   for GetData and SetData, for example, to get or set properties.
  7368.   INPUTS:    theObj                the object whose property we're talking about
  7369.             theProp                the property
  7370.             result                destination VAR for resulting prop object specifier
  7371.   ERRORS:
  7372.   SIDE EFFECTS:
  7373.   NOTES:    (1) if MakePropObjSpec returns noErr, then result is a valid
  7374.               descriptor that the caller is responsible for disposing.  If an
  7375.             error code is returned, result is undefined and doesn't have to
  7376.             be disposed.
  7377.             (2) This is basically a cover proc for MakeObjSpec, which, because of its generality,
  7378.             has more inputs than anyone should have to look at very often.
  7379.             (3) the input theObj is analogous to theCont in MakeObjSpec and
  7380.             related calls, because AppleEvents treats properties as being
  7381.             "contained" in the objects they are properties of
  7382. }
  7383. BEGIN
  7384.   MakePropObjSpec := MakeObjSpec(cProperty,theObj,formPropertyID,
  7385.       typeType,@theProp,SizeOf(theProp),result);
  7386. END;    { MakePropObjSpec }
  7387.  
  7388. {$S QuillNew }
  7389. FUNCTION MakeSelfAddr(VAR addrDesc: AEAddressDesc):    OSErr;
  7390. { create an address descriptor for the current process 
  7391.   INPUTS:    addrDesc    result VAR for the descriptor
  7392.   OUTPUTS:    error code (noErr if none)
  7393.   ERRORS:
  7394.   SIDE EFFECTS:
  7395. }
  7396. VAR procSerNum:        ProcessSerialNumber;
  7397.     myErr:            INTEGER;
  7398. BEGIN
  7399.   procSerNum.highLongOfPSN := 0;
  7400.   procSerNum.lowLongOfPSN := kCurrentProcess;
  7401.   gTempBool := CatchErr(   AECreateDesc(typeProcessSerialNumber,@procSerNum,SizeOf(procSerNum),addrDesc) , 3013 , myErr );
  7402.   MakeSelfAddr := myErr;
  7403. END;    { MakeSelfAddr }
  7404.  
  7405. {$S QuillNew}
  7406. FUNCTION MakeSelTextObj(window: WindowPtr; VAR selTextObj: AEDesc): OSErr;
  7407. { make an object representing the selected text in the given window.
  7408.   The object will represent the text as a range of chars within the
  7409.   window; the window itself will be represented by index.
  7410.   INPUTS:    window            ptr to the window
  7411.               selTextObj        return VAR for the text object
  7412.   OUTPUTS:    error code (noErr if none)
  7413.   NOTES:    07/01/91    BHM        Added "spots" for 0-length selection (insertion pt)
  7414.               10/04/91    BHM        Now replaced by SmartMakeSelTextObj - but I'm leaving
  7415.                                 this here for historical and/or safety reasons
  7416. }
  7417. LABEL 9;
  7418. VAR myErr:        OSErr;
  7419.     wndwObj:    AEDesc;
  7420.     startObj:    AEDesc;
  7421.     endObj:        AEDesc;
  7422.     index:        LongInt;
  7423.     startChar:    LongInt;
  7424.     endChar:    LongInt;
  7425.     spotFlag:    BOOLEAN;
  7426. BEGIN
  7427.   myErr := genericErr;
  7428.   InitSomeDescs(@selTextObj,@wndwObj,@startObj,@endObj,NIL);
  7429.   
  7430.   { make the window object }
  7431.   index := IndexFromWndwPtr(window);    { **CHECK for 0? }
  7432.   IF CatchErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,index,wndwObj) , 16613 , myErr )
  7433.       THEN GOTO 9;
  7434.       
  7435.   { get the start and end of selection }
  7436.   WITH DocumentPeek(window)^.docTE^^ DO
  7437.     BEGIN
  7438.       startChar := selStart+1;    { start counting obj's from 1, not 0 }
  7439.       endChar := selEnd;
  7440.       spotFlag := (selStart = selEnd);
  7441.     END;
  7442.     
  7443.   IF spotFlag THEN
  7444.     BEGIN
  7445.       { "spots" - 0-length strings - aren't represented as ranges }
  7446.       gTempBool := CatchErr(   MakeObjSpecFromIndex(cSpot,wndwObj,startChar,selTextObj) , 16617 , myErr );
  7447.       GOTO 9;
  7448.     END;
  7449.     
  7450.   { not a spot - must represent as range }
  7451.     
  7452.   { make obj for start char }
  7453.   IF CatchErr(   MakeObjSpecFromIndex(cChar,wndwObj,startChar,startObj) , 16614 , myErr)
  7454.       THEN GOTO 9;
  7455.       
  7456.   { now for end char }
  7457.   IF CatchErr(   MakeObjSpecFromIndex(cChar,wndwObj,endChar,endObj) , 16614 , myErr)
  7458.       THEN GOTO 9;
  7459.       
  7460.   { and now for the whole range object }
  7461.   gTempBool := CatchErr(   MakeObjSpecFromRange(cChar,wndwObj,startObj,endObj,selTextObj) , 16615 , myErr);
  7462.   
  7463. 9:  { finish up }
  7464.   gTempBool := CheckErr(   DisposeSomeDescs(@wndwObj,@startObj,@endObj,NIL,NIL) , 16616 );
  7465.   
  7466.   MakeSelTextObj := myErr;
  7467. END;    { MakeSelTextObj }
  7468.  
  7469. {$S QuillNew2}
  7470. PROCEDURE MakeSelTextToken(window: WindowPtr; VAR selTextToken: TextToken);
  7471. { create a text token representing the selected text (which may be an 
  7472.   insertion point) in the given window
  7473.   INPUTS:    window            ptr to the window
  7474.               selTextToken    return VAR for the text token
  7475.   OUTPUTS:    none
  7476.   NOTES:    this routine is almost invariably preceded (although not
  7477.               necessarily immediately) with a get-and-check front window;
  7478.             we may want to roll that in
  7479. }
  7480. BEGIN
  7481.   WITH DocumentPeek(window)^.docTE^^ DO
  7482.     BEGIN
  7483.       selTextToken.tokenOffset := selStart;
  7484.       selTextToken.tokenLength := selEnd - selStart;
  7485.     END;
  7486.     
  7487.   selTextToken.tokenWndw := window;
  7488.   selTextToken.tokenClass := cText;
  7489. END;    { MakeSelTextToken }
  7490.  
  7491.  
  7492. {$S QuillNew2}
  7493. FUNCTION MakeSpotObj(wndwIndex: INTEGER; spotIndex: INTEGER; VAR spotObj: AEDesc): OSErr;
  7494. { create an object specifier for the "spot" (0-length text object) with a given
  7495.   index, and in a window given by its index
  7496.   INPUTS:    wndwIndex        index of the window
  7497.               spotIndex        index for the spot
  7498.             spotObj            return VAR for the object specifier
  7499.   OUTPUTS:    error code (noErr if none)
  7500.   NOTES:    (1) this is a purely abstract obj spec-constructing routine; we
  7501.               don't validate the window, nor how many spots it has
  7502.             (2) we may want to make use of this in MakeSelTextObj
  7503. }
  7504. LABEL 9;
  7505. VAR myErr:        OSErr;
  7506.     wndwObj:    AEDesc;
  7507. BEGIN
  7508.   myErr := genericErr;
  7509.   InitSomeDescs(@wndwObj,@spotObj,NIL,NIL,NIL);
  7510.   
  7511.   { make the window object }
  7512.   IF CatchErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,wndwIndex,wndwObj) , 19413 , myErr )
  7513.       THEN GOTO 9;
  7514.       
  7515.   { make the spot object }
  7516.   gTempBool := CatchErr(   MakeObjSpecFromIndex(cSpot,wndwObj,spotIndex,spotObj) , 19414 , myErr );
  7517.  
  7518. 9:    { finish up }
  7519.   { NOTE:  you never have to dispose spotObj; either this routine succeeds or spotObj is never even created }
  7520.   gTempBool := CheckErr(   AEDisposeDesc(wndwObj) , 19415 );
  7521.   
  7522.   MakeSpotObj := myErr;
  7523. END;    { MakeSpotObj }
  7524.  
  7525.  
  7526.  
  7527. {$S QuillNew}
  7528. FUNCTION MakeStylTextDesc(myTextToken: TextToken; VAR theSTDesc: AEDesc): OSErr;
  7529. { given a text token specifying some text in a window,
  7530.   return an AERecord containing the text and its style
  7531.   information
  7532.   INPUTS:    myTextToken        the text token
  7533.               theSTDesc        return VAR for the resulting descriptor (in this case an AERecord)
  7534.   OUTPUTS:    error code (noErr if none)
  7535. }
  7536. LABEL 9;
  7537. VAR myErr:        OSErr;
  7538.     textDesc:    AEDesc;
  7539.     theWndwTE:    TEHandle;
  7540.     myStylHndl:    StScrpHandle;
  7541.     oldSTDesc:    AEDesc;
  7542. BEGIN
  7543.   myErr := genericErr;
  7544.   InitSomeDescs(@oldSTDesc,@textDesc,@theSTDesc,NIL,NIL);
  7545.   
  7546.   { create the empty record }
  7547.   IF CatchErr(   AECreateList(NIL,0,TRUE,oldSTDesc) , 13313 , myErr ) 
  7548.       THEN GOTO 9;
  7549.       
  7550.   { make a descriptor containing the style-less text}
  7551.   IF CatchErr(   TextTokenToDesc(myTextToken,textDesc) , 13314 , myErr )
  7552.       THEN GOTO 9;
  7553.       
  7554.   { attach it to the record }
  7555.   IF CatchErr(   AEPutKeyDesc(oldSTDesc, keyAEText,textDesc) , 13315 , myErr )
  7556.       THEN GOTO 9;
  7557.       
  7558.   { now get the style info - well, first we have to set things up }
  7559.   WITH myTextToken DO
  7560.     BEGIN
  7561.       { **NOTE:  this changes the selection.  Should we save and reset? }
  7562.       theWndwTE := DocumentPeek(tokenWndw)^.docTE;
  7563.       TESetSelect(tokenOffset,tokenOffset+tokenLength,theWndwTE);
  7564.     END;
  7565.     
  7566.   myStylHndl := GetStylScrap(theWndwTE);
  7567.   IF myStylHndl = NIL THEN
  7568.     BEGIN
  7569.       gTempBool := CatchErr(   stylHndlErr , 13316 , myErr );    { or whatever }
  7570.       GOTO 9;
  7571.     END;
  7572.       
  7573.   { now add that info to the record }
  7574.   HLock(Handle(myStylHndl));
  7575.   myErr := AEPutKeyPtr(oldSTDesc,keyAEStyles,typeScrapStyles,Ptr(myStylHndl^),GetHandleSize(Handle(myStylHndl)));
  7576.   HUnlock(Handle(myStylHndl));
  7577.   IF CheckErr(   myErr , 13317 ) THEN GOTO 9;
  7578.   
  7579.   { now - **AND do I need this?  Is it legit? - coerce the record to typeStyledText }
  7580.   IF CatchErr(   AECoerceDesc(oldSTDesc,typeStyledText,theSTDesc) , 13318 , myErr )
  7581.       THEN GOTO 9;
  7582.       
  7583.   { all looks fine }
  7584.   myErr := noErr;    { not really necessary - when is it? }
  7585.   
  7586. 9:    { finish up }
  7587.   gTempBool := CheckErr( DisposeSomeDescs(@oldSTDesc,@textDesc,NIL,NIL,NIL) , 13319 );
  7588.   
  7589.   MakeStylTextDesc := myErr;
  7590. END;    { MakeStylTextDesc }
  7591.  
  7592. {$S QuillNew2}
  7593. FUNCTION MakeTextRangeObj(wndwIndex: INTEGER; startChar: INTEGER; endChar: INTEGER; 
  7594.     VAR rangeObj: AEDEsc): OSErr;
  7595. { make an object specifier representing the range of characters from startChar to endChar
  7596.   (inclusive) in a given window (specified by its index)
  7597.   INPUTS:    wndwIndex        index of the window
  7598.               startChar        number of the first char in the range
  7599.             endChar            number of the last char in the range
  7600.             rangeObj        return VAR for the object specifier
  7601.   OUTPUTS:    error code (noErr if none)
  7602.   NOTES:    (1) this is a purely abstract obj-spec-maker; we don't
  7603.               validate the window, the number of chars within it, etc.
  7604.             (2) I'm using integers for my indices, but it might be
  7605.             better to use LongInts - **CHECK
  7606.             (3) we may want to make use of this in MakeSelTextObj
  7607. }
  7608. LABEL 9;
  7609. VAR myErr:        OSErr;
  7610.     wndwObj:    AEDesc;
  7611.     startObj:    AEDesc;
  7612.     endObj:        AEDesc;
  7613. BEGIN
  7614.   myErr := genericErr;
  7615.   InitSomeDescs(@wndwObj,@startObj,@endObj,@rangeObj,NIL);
  7616.   
  7617.   { make the window object }
  7618.   IF CatchErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,wndwIndex,wndwObj) , 19513 , myErr )
  7619.       THEN GOTO 9;
  7620.       
  7621.   { make obj for start char }
  7622.   IF CatchErr(   MakeObjSpecFromIndex(cChar,wndwObj,startChar,startObj) , 19514 , myErr)
  7623.       THEN GOTO 9;
  7624.       
  7625.   { now for end char }
  7626.   IF CatchErr(   MakeObjSpecFromIndex(cChar,wndwObj,endChar,endObj) , 19515 , myErr)
  7627.       THEN GOTO 9;
  7628.       
  7629.   { and now for the whole range object }
  7630.   gTempBool := CatchErr(   MakeObjSpecFromRange(cChar,wndwObj,startObj,endObj,rangeObj) , 19516 , myErr);
  7631.   
  7632. 9:    { finish up }
  7633.   { NOTE: in no case do you need to dispose of rangeObj; if the call fails, then it was never even created }
  7634.   gTempBool := CheckErr(   DisposeSomeDescs(@wndwObj,@startObj,@endObj,NIL,NIL) , 19517);
  7635.   
  7636.   MakeTextRangeObj := myErr;
  7637. END;    { MakeTextRangeObj }
  7638.  
  7639.  
  7640. {$S QuillNew}
  7641. PROCEDURE MakeTextTokenForWndw(window: WindowPtr; VAR wndwText: TextToken);
  7642. { given a window, create a text token that represents all the text
  7643.   in the window.
  7644.   INPUTS:    window        ptr to the window
  7645.               wndwText    return VAR for the text token
  7646.   OUTPUTS:    none
  7647. }
  7648. BEGIN
  7649.   WITH wndwText DO
  7650.     BEGIN
  7651.       tokenClass := cChar;    { treat as a range of chars }
  7652.       tokenWndw := window;
  7653.       tokenOffset := 0;
  7654.       tokenLength := DocumentPeek(window)^.docTE^^.teLength;
  7655.     END;
  7656. END;    { MakeTextTokenForWndw }
  7657.  
  7658. {$S QuillNew2}
  7659. FUNCTION MakeWindowList(VAR wndwList: AEDesc; myType: DescType): OSErr;
  7660. { make a list of tokens for all the current windows (used, for example,
  7661.   when accessing "all windows") - you can specify whether you want them
  7662.   labeled as windows (typeMyWndw) or documents (typeMyDoc)
  7663.   INPUTS:    wndwList        return VAR for window list
  7664.               myType            type to be used in tokens (typeMyWndw or 
  7665.                             typeMyDoc)
  7666.   OUTPUTS:    error code (noErr if none)
  7667.   
  7668.   09/09/91    BHM        added myType param to handle documents
  7669. }
  7670. LABEL 9;
  7671. VAR myErr:    OSErr;
  7672.     window:    WindowPtr;
  7673. BEGIN
  7674.   myErr := genericErr;
  7675.   wndwList := gNullDesc;
  7676.   
  7677.   { make the empty list }
  7678.   IF CatchErr(   AECreateList(NIL,0,FALSE,wndwList) , 19913 , myErr )
  7679.       THEN GOTO 9;
  7680.       
  7681.   { step through the windows }
  7682.   window := FrontWindow;
  7683.   WHILE window <> NIL DO
  7684.     BEGIN
  7685.       IF CatchErr(   AEPutPtr(wndwList,0,myType,@window,SizeOf(window)) , 19914 , myErr )
  7686.           THEN GOTO 9;
  7687.       window := WindowPtr(WindowPeek(window)^.nextWindow);
  7688.     END;
  7689.     
  7690. 9:
  7691.   { there are possible errors AFTER the return list is created; if }
  7692.   { there's an error, we'll want to dispose of the list            }
  7693.   
  7694.   IF myErr <> noErr THEN gTempBool := CheckErr(   AEDisposeDesc(wndwList) , 19915 );
  7695.   MakeWindowList := myErr;
  7696. END;    { MakeWindowList }
  7697.  
  7698. {$S QuillNew2}
  7699. FUNCTION MatchToReqList(srcDesc: AEDesc; reqList: AEDesc; bestType: DescType;
  7700.     defType: DescType; VAR dstDesc: AEDesc): OSErr;
  7701. { given a descriptor and a list of types, go down the list and attempt to 
  7702.   coerce the descriptor into the type you find; continue until you succeed.
  7703.   If you come across typeBest, used the supplied bestType value; if you come
  7704.   across typeWildCard, use the supplied defType.  If NONE of the listed types
  7705.   succeed, we'll give one last try with typeWildCard (that is, we'll try defType).
  7706.   
  7707.   For convenience, if the reqList is either a null descriptor (typeNull) or
  7708.   a 0-element list, we treat it as typeWildCard.
  7709.   
  7710.   INPUTS:    srcDesc        the given descriptor
  7711.               reqList        prioritized list of requested types
  7712.             bestType    type to use for typeBest
  7713.             defType        type to use for typeWildCard
  7714.             dstDesc        return VAR for the coerced descriptor
  7715.   OUTPUTS:    error code (noErr if none)
  7716.   NOTES:    (1) routines like this, in many cases, do a lot more copying than Quill
  7717.               really needs (for example, if dstDesc is already of the right type),
  7718.             and we may want to change it or be more particular about when we call
  7719.             it in the future - **CHECK
  7720.             (2) CAUTION - you may NOT use typeBest as a value for bestType or defType;
  7721.             if the AEM got a coercion request with typeBest (in the AECoerce, below),
  7722.             it wouldn't know what to do.  (Putting in typeWildCard for bestType or 
  7723.             defType doesn't make much sense either, but probably wouldn't cause an error)
  7724. }
  7725. LABEL 9;
  7726. VAR myErr:        OSErr;
  7727.     itemCount:    LongInt;
  7728.     i:            LongInt;
  7729.     myType:        DescType;
  7730. BEGIN
  7731.   myErr := genericErr;
  7732.   dstDesc := gNullDesc;
  7733.   
  7734.   { make sure reqList isn't the null descriptor }
  7735.   IF reqList.descriptorType <> typeNull THEN
  7736.     BEGIN
  7737.       { not null desc - should be list; count the items }
  7738.       IF CatchErr(   AECountItems(reqList,itemCount) , 23813 , myErr ) THEN GOTO 9;
  7739.       
  7740.       { make sure list isn't empty }
  7741.       IF itemCount <> 0 THEN
  7742.         BEGIN
  7743.         
  7744.           FOR i := 1 TO itemCount DO
  7745.             BEGIN
  7746.               { get ith type in the list }
  7747.               IF CatchErr(   AEGetNthPtr(reqList,i,typeType,gReturnedKeywd,gReturnedType,@myType,
  7748.                   SizeOf(myType),gActSize) , 23814 , myErr ) THEN GOTO 9;
  7749.                   
  7750.               { check against "magic" types }
  7751.               IF myType = typeBest THEN myType := bestType
  7752.               ELSE IF myType = typeWildCard THEN myType := defType;
  7753.               
  7754.               { we could **CHECK for typeBest here if we wanted to - it shouldn't occur }
  7755.               
  7756.               myErr := AECoerceDesc(srcDesc,myType,dstDesc);
  7757.               IF myErr = noErr THEN GOTO 9;    { successful coercion, we're done }
  7758.             END;    { of loop }
  7759.             
  7760.         END;        { of itemCount <> 0 }
  7761.     END;            { of reqList not null desc }
  7762.  
  7763.   { we only get here if (a) reqList is null desc, or (b) reqList has 0 items, or (c) we }
  7764.   { failed on every type in the list.  In ANY of those cases, we need to try defType.   } 
  7765.   
  7766.   gTempBool := CatchErr(   AECoerceDesc(srcDesc,defType,dstDesc) , 23815 , myErr );
  7767.     
  7768. 9:
  7769.   MatchToReqList := myErr;
  7770. END;    { MatchToReqList }
  7771.  
  7772. {$S QuillNew }
  7773. FUNCTION MightWeInteract(interMode: LongInt; VAR mayInteract: BOOLEAN):  OSErr;
  7774. { this is a somewhat special-purpose routine I use in the PrintDocs Event
  7775.   handler.  Based on the interMode (which is generally obtained from the
  7776.   SendMode attr of an AppleEvent), it MAY call AEInteractWithUser and
  7777.   report on the results.  Here's the rules:
  7778.   (1)    if interMode = kAENeverInteract, it doesn't call AEInteractWithUser,
  7779.           always returns FALSE in mayInteract, and always returns a noErr result
  7780.   (2)    if interMode = kAECanInteract, it calls AEInteractWithUser.  If that
  7781.           call fails, FALSE is returned in mayInteract; but the routine returns
  7782.         a noErr (i.e., you can't interact, but you should keep going, since the
  7783.         mode was only "can" interact, not always).  If the AEInteractWithUser
  7784.         succeeds, TRUE is returned in mayInteract and noErr as a function
  7785.         result
  7786.   (3)    if interMode = kAEAlwaysInteract, it calls AEInteractWithUser; if that
  7787.         call succeeds, TRUE is returned in mayInteract  and noErr as a function
  7788.         result; but if it fails, FALSE is returned in mayInteract and the error
  7789.         code from AEInteractWithUser is returned as a function result (because this 
  7790.         is an "always" interact case, so we fail if we can't interact)
  7791.   INPUTS:    interMode        one of the 3 interaction mode constants
  7792.               mayInteract        result VAR to tell the user if it's ok to go
  7793.                             ahead with some interactive activity (TRUE if ok,
  7794.                             FALSE o.w.)
  7795.   OUTPUTS:    error code, noErr if none.  Note that the "never" and "can"
  7796.               cases don't generate an error regardless of the result of
  7797.             AEInteractWithUser
  7798.   SIDE EFFECTS:    may bring the app forward for interaction
  7799.   NOTES:    (1)    if interMode is an illegal value (not one of the 3),
  7800.                   we return errAEUnknownSendMode
  7801.             (2)    AEInteractWithUser is called with no time-out,
  7802.                 no Notification Manager record, and no idle proc
  7803. }
  7804. LABEL 9;
  7805. VAR myErr:    OSErr;
  7806. BEGIN
  7807.   myErr := genericErr;
  7808.   mayInteract := FALSE;
  7809.  
  7810.   IF interMode = kAENeverInteract THEN
  7811.     BEGIN
  7812.       myErr := noErr;
  7813.       mayInteract := FALSE;
  7814.       GOTO 9;    { finish up }
  7815.     END;
  7816.     
  7817.   IF interMode = kAECanInteract THEN
  7818.     BEGIN
  7819.       myErr := noErr;
  7820.       mayInteract := ( AEInteractWithUser(kNoTimeOut,NIL,NIL) = noErr );
  7821.       GOTO 9;
  7822.     END;
  7823.     
  7824.   IF interMode = kAEAlwaysInteract THEN
  7825.     BEGIN
  7826.       myErr := AEInteractWithUser(kNoTimeOut,NIL,NIL);
  7827.       mayInteract := (myErr = noErr);
  7828.       GOTO 9;
  7829.     END;
  7830.     
  7831.   { illegal interMode value }
  7832.   
  7833.   myErr := errAEUnknownSendMode;
  7834.   
  7835. 9:    { finish up }
  7836.   MightWeInteract := myErr;
  7837. END;    { MightWeInteract }
  7838.  
  7839. {$S QuillNew2}
  7840. FUNCTION MoveToken(theToken: AEDesc; relObjToken: AEDesc; position: DescType): OSErr;
  7841. { this routine takes a token representing a single object and moves the object
  7842.   to a given location.  The location is specified by an object token (relObjToken)
  7843.   and a position modifier (position).  If position is kAEBefore, kAEAfter, or 
  7844.   kAEReplace, then the the object is moved to before, after, or into (replacing)
  7845.   the relObjToken; if it's kAEBeginning or kAEEnd, then the relObjToken is treated
  7846.   as a container, and the object is moved into it at its beginning or end.
  7847.   
  7848.   IMPORTANT NOTE:    relObjToken is assumed to be a token, already resolved, not
  7849.                       a raw object specifier (if we're doing a list, we don't want
  7850.                     to resolve it every time through this routine); and it must
  7851.                     specify a single object, not a list of objects
  7852.                     
  7853.   INPUTS:    theToken        token representing a single object to be moved
  7854.               relObjToken        another token used (with position) to specify the 
  7855.                             location to move the first object to
  7856.             position        an enumerated value used to help specify the location
  7857.                             to move the first object to
  7858.                             
  7859.   See the above description for valid values and interpretations of relObjToken
  7860.   and position
  7861. }
  7862. LABEL 9;
  7863. VAR myErr:        OSErr;
  7864.     myWndw:        WindowPtr;
  7865.     relObjType:    DescType;    { token type, not class of original obj }
  7866.     bWindow:    WindowPtr;
  7867. BEGIN
  7868.   myErr := genericErr;
  7869.   
  7870.   { windows/docs are the only thing we know how to move right now }
  7871.   IF (theToken.descriptorType <> typeMyWndw) & (theToken.descriptorType <> typeMyDoc) THEN
  7872.     BEGIN
  7873.       gTempBool := CatchErr(   errAEWrongDataType , 23213 , myErr );
  7874.       GOTO 9;
  7875.     END;
  7876.     
  7877.   { get the window/doc}
  7878.   IF CatchErr(   MyAECoerceDescPtr(theToken,typeWildCard,@myWndw,SizeOf(myWndw),gActSize) , 
  7879.       23214 , myErr ) THEN GOTO 9;
  7880.       
  7881.   { now work out the parameters for MySendWindow }
  7882.   { NOTE that we know at least one window exists, so we don't have to worry about empty container }
  7883.   
  7884.   relObjType := relObjToken.descriptorType;    { handy info to have around }
  7885.   
  7886.   IF position = kAEBeginning THEN
  7887.     BEGIN
  7888.       { relObjToken better be null }
  7889.       IF relObjType <> typeNull THEN
  7890.         BEGIN
  7891.           gTempBool := CatchErr(   errAEWrongDataType , 23215 , myErr );
  7892.           GOTO 9;
  7893.         END;
  7894.         
  7895.       { let's rephrase this as "before the first window" }
  7896.       position := kAEBefore;
  7897.       bWindow := FrontWindow;    { guaranteed to exist }
  7898.     END
  7899.     
  7900.   ELSE IF position = kAEEnd THEN
  7901.     BEGIN
  7902.       IF relObjType <> typeNull THEN
  7903.         BEGIN
  7904.           gTempBool := CatchErr(   errAEWrongDataType , 23216 , myErr );
  7905.           GOTO 9;
  7906.         END;
  7907.         
  7908.       { let's rephrase this as "after the last window" }
  7909.       position := kAEAfter;
  7910.       bWindow := BackWindow;    { guaranteed to exist }
  7911.     END
  7912.     
  7913.   ELSE
  7914.     BEGIN
  7915.       { we're in the before/after/replace case; get the other window }
  7916.       IF (relObjType <> typeMyWndw) & (relObjType <> typeMyDoc) THEN
  7917.         BEGIN
  7918.           gTempBool := CatchErr(   errAEWrongDataType , 23217 , myErr );
  7919.           GOTO 9;
  7920.         END;
  7921.         
  7922.       { get the window/doc }
  7923.       IF CatchErr(   MyAECoerceDescPtr(relObjToken,typeWildCard,@bWindow,SizeOf(bWindow),gActSize) , 
  7924.           23214 , myErr ) THEN GOTO 9;
  7925.     END;
  7926.     
  7927.   { we are now set up for MySendWindow }
  7928.   gTempBool := CatchErr(   MySendWindow(myWndw,bWindow,position) , 23215 , myErr );
  7929.   
  7930. 9:
  7931.   MoveToken := myErr;
  7932. END;    { MoveToken }
  7933.  
  7934. {$S QuillNew2}
  7935. FUNCTION MoveTokenList(theList: AEDesc; relObjToken: AEDesc; position: DescType): OSErr;
  7936. { this routine takes a list of tokens (or a list whose ultimate nodes are tokens;
  7937.   we permit lists of lists, etc.) and moves every object in the list to a particular
  7938.   location.  We work backwards through the list to preserve order and minimize side-effects.
  7939.   
  7940.   Two parameters (relObjToken and position) determine where the objects are to be moved to.
  7941.   relObjToken should already be resolved, and should be a token, not a list of tokens.
  7942.   
  7943.   Naturally, this routine really just iterates through the list and hands over any tokens
  7944.   it finds to MoveToken.  See that routine for a description of the parameters.
  7945.   
  7946.   INPUTS:    see MoveToken
  7947.   OUTPUTS:    error code (noErr if none)
  7948. }
  7949. LABEL 9;
  7950. VAR    myErr:        OSErr; 
  7951.     itemCount:    LongInt;
  7952.     i:            LongInt;
  7953.     thisItem:    AEDesc;
  7954. BEGIN
  7955.   myErr := genericErr;
  7956.   thisItem := gNullDesc;
  7957.   
  7958.   IF CatchErr(   AECountItems(theList,itemCount) , 23113 , myErr ) THEN GOTO 9;
  7959.   IF itemCount = 0 THEN GOTO 9;    { empty list, we're done }
  7960.   
  7961.   { loop through the items }
  7962.   FOR i := itemCount DOWNTO 1 DO
  7963.     BEGIN
  7964.       { get the item }
  7965.       IF CatchErr(   AEGetNthDesc(theList,i,typeWildCard,gReturnedKeywd,thisItem) , 23114 ,
  7966.           myErr ) THEN GOTO 9;
  7967.           
  7968.       { dispatch on list vs. non-list }
  7969.       IF thisItem.descriptorType = typeAEList THEN
  7970.         BEGIN
  7971.           IF CatchErr(   MoveTokenList(thisItem,relObjToken,position) , 23115 , myErr )
  7972.               THEN GOTO 9;
  7973.         END
  7974.       ELSE
  7975.         BEGIN
  7976.           IF CatchErr(   MoveToken(thisItem,relObjToken,position) , 23116 , myErr )
  7977.               THEN GOTO 9;
  7978.         END;
  7979.         
  7980.       { dispose of item }
  7981.       gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 23117 );
  7982.       thisItem := gNullDesc;
  7983.     END;    { FOR loop }
  7984.     
  7985. 9:
  7986.   gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 23118 );
  7987.   MoveTokenList := myErr;
  7988. END;    { MoveTokenList }
  7989.  
  7990. {$S QuillNew }      
  7991. FUNCTION MyAEChangeDescType(VAR theDesc: AEDesc; newType: DescType): OSErr;
  7992. { this routine takes an existing descriptor, coerces it to a new type,
  7993.   and returns it in the same descriptor.  The caller is responsible for
  7994.   disposing of that one descriptor, regardless of whether the call fails
  7995.   or succeeds.
  7996.   INPUTS:    theDesc        the descriptor to be changed
  7997.               newType        the type to coerce it to
  7998.   OUTPUTS:    error code (noErr if none).  If the call fails, then the
  7999.               descriptor is unchanged
  8000.   ERRORS:
  8001.   SIDE EFFECTS:
  8002. }
  8003. LABEL 9;
  8004. VAR myErr:        OSErr;
  8005.     newDesc:    AEDesc;
  8006. BEGIN
  8007.   myErr := AECoerceDesc(theDesc,newType,newDesc);
  8008.   IF myErr <> noErr THEN GOTO 9;    { must set function result }
  8009.   myErr := AEDisposeDesc(theDesc);
  8010.   IF myErr <> noErr THEN GOTO 9;
  8011.   theDesc := newDesc;    { **CHECK - is this legit? }
  8012. 9:    { set function result }
  8013.   MyAEChangeDescType := myErr;
  8014. END;  { MyAEChangeDescType }
  8015.  
  8016. {$S QuillNew}
  8017. FUNCTION MyAECoerceDescPtr(theAEDesc: AEDesc; toType: DescType; dataPtr: Ptr;
  8018.     maximumSize: Size; VAR actualSize: Size):  OSErr;
  8019. { this routine plugs a hole that's been nagging at me in the AppleEvents
  8020.   interface.  It takes a descriptor and coerces it to a desired type; but
  8021.   instead of returning a descriptor, it returns data in a buffer specified
  8022.   by the caller.
  8023.   INPUTS:    theAEDesc        descriptor to be coerced
  8024.               toType            type to coerce it to
  8025.             dataPtr            ptr to data buffer
  8026.             maximumSize        maximum length in bytes of data to be returned
  8027.             actualSize        actual length in bytes of data for the descriptor
  8028.   OUTPUTS:    error code (noErr if none)
  8029.   ERRORS:
  8030.   SIDE EFFECTS:
  8031.   NOTES:    12/16/91    BHM        (1) Changed to avoid unecessary duplication when the type
  8032.                                   doesn't really change (this should also enable it to handle
  8033.                                 typeWildCard better)
  8034.                                 (2) We don't need to dispose of newDesc because it is a direct
  8035.                                 copy (not a duplicate) of either theAEDesc or resultDesc - that
  8036.                                 is, it contains the same handle
  8037. }
  8038. LABEL 9;
  8039. VAR myErr:            INTEGER;
  8040.     newDesc:        AEDesc;
  8041.     resultDesc:        AEDesc;
  8042.     transferSize:    Size;
  8043. BEGIN
  8044.   myErr := errAECoercionFail;
  8045.   resultDesc := gNullDesc;
  8046.   
  8047.   { to avoid unnecessary duplication, check old type vs. new type }
  8048.   IF (theAEDesc.descriptorType = toType) OR (toType = typeWildCard) 
  8049.       THEN newDesc := theAEDesc
  8050.   ELSE
  8051.     BEGIN
  8052.       { must coerce to new type }
  8053.       IF QuietCatchErr(   AECoerceDesc(theAEDesc,toType,resultDesc) , myErr ) THEN GOTO 9;
  8054.       newDesc := resultDesc;
  8055.     END;
  8056.         
  8057.   WITH newDesc DO
  8058.     BEGIN
  8059.       { get the size }
  8060.       actualSize := GetHandleSize(dataHandle);
  8061.       IF QuietCatchErr(   MemError , myErr ) THEN GOTO 9;
  8062.     
  8063.       { calculate number of bytes to move }
  8064.       transferSize := actualSize;
  8065.       IF maximumSize < transferSize THEN transferSize := maximumSize;
  8066.     
  8067.       { move the data }
  8068.       HLock(dataHandle);
  8069.       BlockMove(dataHandle^,dataPtr,transferSize);
  8070.       HUnlock(dataHandle);
  8071.     END;    { of WITH newDesc }
  8072.     
  8073.   { everything fine }
  8074.   myErr := noErr;
  8075.     
  8076. 9:    { finish up }
  8077.   gTempBool := CheckErr(   AEDisposeDesc(resultDesc) , 2215 );
  8078.   MyAECoerceDescPtr := myErr;
  8079. END;    { MyAECoerceDescPtr }
  8080.  
  8081. {$S QuillNew2}
  8082. PROCEDURE MyAEDoKey(key: CHAR; window: WindowPtr);
  8083. { this routine is called after we've handled a keydown
  8084.   event (one that generates a character or a delete, not
  8085.   a cmd-key event); it does what's necessary to record
  8086.   typing for AppleEvents.  The character is added to a 
  8087.   buffer; later, when a non-key event takes place, the
  8088.   buffer is bundled up as a text desc and shipped off in
  8089.   a Set Data event to replace the selection (or, at least,
  8090.   the selection as it was when the user started typing).
  8091.   The delete key requires special handling (and, if it's
  8092.   the first key to go into the buffer, VERY special handling).
  8093.   
  8094.   Note that the AppleEvent, when it's sent, will be marked
  8095.   "record only"; we've already changed the text in real-time 
  8096.   when the user was typing.
  8097.   
  8098.   INPUTS:    key            the character that was typed
  8099.               window        ptr to the active window
  8100.   OUTPUTS:    none
  8101.   NOTES:    we may want to do some more sophisticated 
  8102.               error-handling
  8103. }
  8104. BEGIN
  8105.   IF keyBuffer.bufEmpty THEN StartKeyBuffering(key,window)
  8106.   ELSE ContinueKeyBuffering(key,window);
  8107. END;    { MyAEDoKey }
  8108.  
  8109.  
  8110. {$S QuillNew}
  8111. PROCEDURE MyBringWndwFront(window: WindowPtr);
  8112. { this routine sends an AppleEvent Move event to move
  8113.   the given window to before the front window (thus
  8114.   bringing the window to the front)
  8115.   INPUTS:    window        ptr to the window
  8116.   OUTPUTS:    none
  8117. }
  8118. LABEL 9;
  8119. VAR index:            INTEGER;
  8120.     wndwObj:        AEDesc;
  8121.     insertionLoc:    AEDesc;
  8122.     myAppleEvent:    AppleEvent;
  8123.     defReply:        AppleEvent;
  8124. BEGIN
  8125.   InitSomeDescs(@wndwObj,@myAppleEvent,@defReply,@insertionLoc,NIL);
  8126.  
  8127.   index := IndexFromWndwPtr(window);
  8128.   
  8129.   IF index = 0 THEN
  8130.     BEGIN
  8131.       { no such window }
  8132.       DoMyErr(   errAEBadData , 19213 );
  8133.       GOTO 9;
  8134.     END;
  8135.     
  8136.   { make an object for the given window }
  8137.   IF CheckErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,index,wndwObj) , 19214 ) THEN GOTO 9;
  8138.   
  8139.   { create the insertion loc ("beginning of null container") }
  8140.   IF CheckErr(   MakeInsertionLoc(gNullDesc,kAEBeginning,insertionLoc) , 19216 ) THEN GOTO 9;
  8141.  
  8142.   { create the AppleEvent }
  8143.   IF CheckErr(   AECreateAppleEvent(kAECoreSuite,kAEMove,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,myAppleEvent) , 
  8144.       19216 ) THEN GOTO 9;
  8145.       
  8146.   { add direct object to AppleEvent }
  8147.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyDirectObject,wndwObj) , 19217 ) THEN GOTO 9;
  8148.   
  8149.   { add insertion loc to AppleEvent }
  8150.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyAEInsertHere,insertionLoc) , 19218 ) THEN GOTO 9;
  8151.   
  8152.       
  8153.   { send AppleEvent }
  8154.   gTempBool := CheckErr(   AESend(myAppleEvent,defReply,kAENoReply+kAECanInteract,kAENormalPriority,kAEDefaultTimeOut,NIL,NIL) , 
  8155.       19219 );
  8156.       
  8157. 9:    { finish up }
  8158.   gTempBool := CheckErr(   DisposeSomeDescs(@wndwObj,@myAppleEvent,@defReply,@insertionLoc,NIL) , 19220 );
  8159. END;    { MyBringWndwFront }
  8160.  
  8161. {$S QuillNew}
  8162. FUNCTION MyCompareProc(oper: DescType; obj1: AEDesc; obj2: AEDesc; VAR result: BOOLEAN): OSErr;
  8163. LABEL 9;
  8164. VAR myErr:        OSErr;
  8165.     aDesc:    AEDesc;
  8166.     bDesc:    AEDesc;
  8167. BEGIN
  8168.   MyCompareProc := genericErr;
  8169.   InitSomeDescs(@aDesc,@bDesc,NIL,NIL,NIL);
  8170.         
  8171.   { get two text descriptors }
  8172.   IF NOT(AECanCompare(obj1.descriptorType)) THEN
  8173.       BEGIN
  8174.           IF CatchErr(   GetTextFromDesc(obj1,aDesc) , 15813 , myErr ) THEN GOTO 9;
  8175.     END
  8176.   ELSE
  8177.     BEGIN
  8178.       IF CatchErr(   AEDuplicateDesc(obj1,aDesc) , 15817 , myErr ) THEN GOTO 9;
  8179.     END;
  8180.   
  8181.   IF NOT(AECanCompare(obj2.descriptorType)) THEN
  8182.       BEGIN
  8183.           IF CatchErr(   GetTextFromDesc(obj2,bDesc) , 15814 , myErr ) THEN GOTO 9;
  8184.     END
  8185.   ELSE
  8186.     BEGIN
  8187.       IF CatchErr(   AEDuplicateDesc(obj2,bDesc) , 15818 , myErr ) THEN GOTO 9;
  8188.     END;
  8189.   
  8190.   { now, compare them }
  8191.   IF CatchErr(   AEStandardCompare(oper, aDesc, bDesc, result) , 15815 , myErr ) THEN GOTO 9;
  8192.   
  8193.  9:
  8194.   gTempBool := CheckErr( DisposeSomeDescs(@aDesc,@bDesc,NIL,NIL,NIL), 15816);
  8195.   MyCompareProc := myErr;
  8196.  
  8197. END;    { MyCompareProc }
  8198.  
  8199.  
  8200. {$S QuillNew}
  8201. FUNCTION MyCountProc(desiredType: DescType; containerClass: DescType;
  8202.     container: AEDesc; VAR result: LongInt): OSErr;
  8203. { so far all I count is:
  8204.   (1) the number of active windows in the app;
  8205.   (2) the number of chars/words/lines/items/spots in a window or some text
  8206.   I realized that I wasn't really using the containerClass, so I wrote an
  8207.   "inner" routine that doesn't take that parameter (and is useful elsewhere)
  8208. }
  8209. BEGIN
  8210.   MyCountProc := RealCountProc(desiredType,container,result);
  8211. END;    { MyCountProc }
  8212.  
  8213. {$S QuillNew }
  8214. FUNCTION MyCreateFSS(fileName: Str255; VAR fileSpec: FSSpec):  OSErr;
  8215. { use the current default volume and directory to create a file 
  8216.   spec from a file name
  8217.   INPUTS:    fileName        intended name for the file
  8218.               fileSpec        result VAR for file spec
  8219.   OUTPUTS:    error code (noErr if none)
  8220.   ERRORS:
  8221.   SIDE EFFECTS:
  8222. }
  8223. VAR theVRefNum:    INTEGER;
  8224.     theDirID:    LongInt;
  8225.     myErr:        INTEGER;
  8226.     name:        Str255;
  8227. BEGIN
  8228.   myErr := HGetVol(@name,theVRefNum,theDirID);
  8229.   IF myErr = noErr THEN WITH fileSpec DO
  8230.     BEGIN
  8231.       vRefNum := theVRefNum;
  8232.       parID := theDirID;
  8233.       name := fileName;
  8234.     END;
  8235.   MyCreateFSS := myErr;
  8236. END;  { MyCreateFSS }
  8237.  
  8238. {$S QuillNew}
  8239. FUNCTION MyDoCopy(window: WindowPtr): OSErr;
  8240. { copy the selection from the specified
  8241.   window and put it into the desk scrap
  8242.   INPUTS:    window        ptr to the window
  8243.   OUTPUTS:    error code (noErr if none)
  8244.   NOTES:    (1) this is straight from TEStyleSample; I'm not sure
  8245.               why it's so different from their Cut routine.
  8246. }
  8247. LABEL 9;
  8248. VAR myErr:    OSErr;
  8249. BEGIN
  8250.   IF CatchErr(   ZeroScrap , 17713 , myErr ) THEN GOTO 9;
  8251.   TECopy(DocumentPeek(window)^.docTE);
  8252. 9:
  8253.   MyDoCopy := myErr;
  8254. END;    { MyDoCopy }
  8255.  
  8256.  
  8257. {$S QuillNew}
  8258. FUNCTION MyDoCut(window: WindowPtr): OSErr;
  8259. { cut the selection from the the specified window 
  8260.   and put it into the desk scrap.
  8261.   INPUTS:    window        the window
  8262.   OUTPUTS:    error code (noErr if none)
  8263.   NOTES:    **CHECK - I'm just going by TEStyleSample here . . . .
  8264.               (apparently new-style TE records don't need TEFromScrap
  8265.             and TEToScrap)  Also, I'm not sure what errors I want
  8266.             to hand back.  I'll get back to this.
  8267. }
  8268. LABEL 9;
  8269. VAR myErr:        OSErr;
  8270.     total:        LongInt;
  8271.     contig:        LongInt;
  8272.     myTEHndl:    TEHandle;
  8273. BEGIN
  8274.   myErr := genericErr;
  8275.   
  8276.   IF CatchErr(   ZeroScrap , 17413 , myErr ) THEN GOTO 9;
  8277.   
  8278.   PurgeSpace(total,contig);
  8279.   
  8280.   myTEHndl := DocumentPeek(window)^.docTE;
  8281.   IF myTEHndl^^.selEnd - myTEHndl^^.selStart + kTESlop > contig THEN
  8282.     BEGIN
  8283.       gTempBool := CatchErr(   memFullErr , 17414 , myErr );    { **CHECK - TEStyleSample triggered eNoSpaceCut }
  8284.       GOTO 9;
  8285.     END;
  8286.     
  8287.   TECut(myTEHndl);
  8288.   DirtyWindow(window);
  8289.   myErr := noErr;
  8290.   
  8291. 9:    { finish up }
  8292.   MyDoCut := myErr;
  8293. END;    { MyDoCut }
  8294.  
  8295. {$S QuillNew}
  8296. FUNCTION MyDoPaste(window: WindowPtr): OSErr;
  8297. { paste whatever's in the desk scrap into the selection
  8298.   in the given window.
  8299.   INPUTS:    window        ptr to the window
  8300.   OUTPUTS:    error code (noErr if none)
  8301.   NOTES:    (1) this is taken right from TEStyleSample, and can
  8302.               probably stand some improvement
  8303.               (2) this is good enough for the menu Paste command,
  8304.               but may have to get smarter when we put in the
  8305.             other parameters the Paste event can have - **CHECK
  8306. }
  8307. LABEL 9;
  8308. VAR myErr:        OSErr;
  8309.     myTEHndl:    TEHandle;
  8310.     aHandle:    Handle;
  8311.     oldSize:    LongInt;
  8312.     newSize:    LongInt;
  8313. BEGIN
  8314.   myErr := genericErr;
  8315.   
  8316.   myTEHndl := DocumentPeek(window)^.docTE;
  8317.   
  8318.   WITH myTEHndl^^ DO
  8319.       IF TEGetScrapLen + teLength - (selEnd - selStart) > kMaxTELength THEN
  8320.         BEGIN
  8321.           { too big to be pasted in }
  8322.           gTempBool := CatchErr( errCantPaste , 18113 , myErr );    { TEStyleSample triggers eExceedPaste here }
  8323.           GOTO 9;
  8324.         END;
  8325.         
  8326.   aHandle := Handle(TEGetText(myTEHndl));
  8327.   oldSize := GetHandleSize(aHandle);
  8328.   newSize := oldSize + TEGetScrapLen + kTESlop;
  8329.   SetHandleSize(aHandle,newSize);
  8330.   myErr := MemError;
  8331.   SetHandleSize(aHandle,oldSize);
  8332.   
  8333.   IF CheckErr( myErr , 18114 ) THEN GOTO 9;    { TEStyleSample triggers eNoSpacePaste here }
  8334.   
  8335.   TEStylPaste(myTEHndl);
  8336.   DirtyWindow(window);
  8337.   myErr := noErr;
  8338.   
  8339. 9:    { finish up }
  8340.  
  8341.   MyDoPaste := myErr;
  8342. END;    { MyDoPaste }
  8343.  
  8344.  
  8345. {$S QuillNew}
  8346. FUNCTION MyGetTextElem(textPtr: Ptr; textLength: LongInt; delChar: SignedByte;
  8347.     elemIndex: LongInt; VAR elemOffset: LongInt; VAR elemLength:  LongInt): OSErr;
  8348. { this routine is used to find lines or items in a piece of text.  The text is
  8349.   given by a ptr to its first char and a length (which can be 0).  The delChar
  8350.   is used to delimit elements:  if delChar = carriage return then you're talking
  8351.   about lines, if = comma then items.  (Any other character could also be used.)
  8352.   The particular element is given by its index within the text:  1 for the first
  8353.   such element, 2 for the second, etc.  The routine returns an offset (from textPtr)
  8354.   to the first character of the element, and the length of the element.
  8355.   
  8356.   An element is any delimiter-free stretch of contiguous bytes between two
  8357.   delimiters - except that the text boundaries also delimit elements, so e.g.
  8358.   all the characters up to (but not including) the first delimiter character 
  8359.   constitute the first element.  (Same for all the chars after the last delmiter,
  8360.   mutatis mutandis.)  Elements can be of 0 length, e.g. the item between two
  8361.   adjacent commas.  The element does not include the delimiters.
  8362.   Any text has at least one element; even 0-length text has exactly one
  8363.   0-length line (also, one 0-length item).
  8364.   
  8365.   INPUTS:    textPtr            ptr to first char of the text
  8366.               textLength        length of the text; characters after this are ignored
  8367.             delChar            delimiter character
  8368.             elemIndex        number of the element within the text (1 for first element,
  8369.                             2 for second, etc.)
  8370.             elemOffset        return VAR for offset from textPtr to the first char of
  8371.                             the element (an offset of 0 refers to the first char of the text)
  8372.             elemLength        return VAR for the length of the element
  8373.   OUTPUTS:    noErr if the element is found; errAEIllegalIndex if there aren't that many
  8374.               elements, or if elemIndex < 0; errAECorruptData if textLength < 0
  8375.   NOTES:    **IMPORTANT - this routine is NOT used to get words or characters.  It's
  8376.               only for lines and items.
  8377. }
  8378. LABEL 9;
  8379. VAR myErr:            OSErr;
  8380.     endPtr:            Ptr;
  8381.     endPlus1Ptr:    Ptr;
  8382.     elemPtr:        Ptr;
  8383.     elemCount:        LongInt;
  8384.     delPtr:            Ptr;
  8385. BEGIN
  8386.   myErr := errAEIllegalIndex;    { most likely error, if any }
  8387.   elemOffset := -1;
  8388.   elemLength := -1;    { illegal values, easily recognized }
  8389.   
  8390.   IF textLength < 0 THEN 
  8391.     BEGIN
  8392.       myErr := errAECorruptData;    { bad text }
  8393.       GOTO 9;
  8394.     END;
  8395.     
  8396.   IF elemIndex < 0 THEN GOTO 9;    { bad index }
  8397.   
  8398.   endPtr := Ptr(ORD(textPtr) + textLength - 1);    { ptr to last char of text }
  8399.   { NOTE:  for 0-length text, endPtr is 1 LESS then textPtr; our lower-level
  8400.     routines know how to deal with this.  See e.g. ScanToDelimiter }
  8401.   endPlus1Ptr := Ptr(ORD(endPtr) + 1);    { handy to have around }
  8402.     
  8403.   elemPtr := textPtr;
  8404.   elemCount := 1;
  8405.   
  8406.   WHILE TRUE DO    { repeat forever, sort of }
  8407.     BEGIN
  8408.       { we come in at the start of an element; let's get its end }
  8409.       ScanToDelimiter(elemPtr,endPtr,delChar,delPtr);
  8410.       
  8411.       { now, is it the right element? }
  8412.       IF elemCount = elemIndex THEN
  8413.         BEGIN
  8414.           { yes }
  8415.           elemOffset := ORD(elemPtr) - ORD(textPtr);
  8416.           elemLength := ORD(delPtr) - ORD(elemPtr);
  8417.           myErr := noErr;
  8418.           GOTO 9;
  8419.         END;
  8420.         
  8421.       { not the right element, try the next }
  8422.       IF delPtr = endPlus1Ptr THEN GOTO 9;    { there isn't any next element }
  8423.       
  8424.       { yes, there is, and here's where it starts }
  8425.       elemPtr := Ptr(ORD(delPtr)+1);
  8426.       elemCount := elemCount+1;
  8427.     END;    { of WHILE loop }
  8428.     
  8429. 9:    { finish up}
  8430.   MyGetTextElem := myErr;
  8431. END;    { MyGetTextElem }
  8432.  
  8433. {$S QuillNew}
  8434. FUNCTION MyGetWord(textPtr: Ptr; textLength: LongInt; wordIndex: LongInt;
  8435.     VAR wordOffset: LongInt; VAR wordLength: LongInt): OSErr;
  8436. { find the nth word in a piece of text.  The text is given by a ptr to 
  8437.   its first char and a length.  The word is specified by its index in the 
  8438.   text (1 for first word, 2 for second, etc.).  The routine returns an
  8439.   offset (from textPtr) to the first char of the word, and the word's 
  8440.   length.
  8441.   
  8442.   A word is any stretch of contiguous bytes that contains no break characters,
  8443.   is of positive length, and is bounded by break characters and/or the start
  8444.   of the text and/or the end of the text.  Even text with no break characters
  8445.   can contain a word (the text "alpha" has 1 word).  However, some text contains 
  8446.   no words at all, e.g. a run of 17 spaces.  Text with 0 length contains no words.
  8447.   By definition a word cannot be of length 0.
  8448.   
  8449.   Break characters are defined by the routines ScanToBreak and ScanToNonBreak.
  8450.   As currently implemented, they think spaces and carriage returns are breaks,
  8451.   and nothing else.
  8452.   
  8453.   INPUT:    textPtr            ptr to first char of text
  8454.               textLength        length of the text
  8455.             wordIndex        number of the word in the text (1 for first word, 
  8456.                             2 for second, etc.)
  8457.             wordOffset        return VAR for offset from textPtr of first char
  8458.                             of the word (an offset of 0 refers to the first
  8459.                             char of the text)
  8460.             wordLength        return VAR for the length of the word
  8461.   OUTPUTS:    noErr if the word is found; errAEIllegalIndex if there aren't that
  8462.               many words, or if wordIndex < 0; errAECorruptData if textLength < 0
  8463. }
  8464. LABEL 9;
  8465. VAR myErr:            OSErr;
  8466.     endPtr:            Ptr;
  8467.     endPlus1Ptr:    Ptr;
  8468.     wordPtr:        Ptr;
  8469.     wordCount:        LongInt;
  8470.     breakPtr:        Ptr;
  8471. BEGIN
  8472.   myErr := errAEIllegalIndex;    { most likely error, if any }
  8473.   wordOffset := -1;
  8474.   wordLength := -1;    { illegal values, easily recognized }
  8475.   
  8476.   IF textLength < 0 THEN
  8477.     BEGIN
  8478.       myErr := errAECorruptData;    { bad text }
  8479.       GOTO 9;
  8480.     END;
  8481.     
  8482.   IF wordIndex < 0 THEN GOTO 9;        { bad index }
  8483.   IF textLength < 1 THEN GOTO 9;    { no words, easy fail }
  8484.   
  8485.   
  8486.   IF wordIndex < 0 THEN GOTO 9;    { bad index }
  8487.     
  8488.     
  8489.   IF textLength < 1 THEN GOTO 9;    { bad index }
  8490.     
  8491.   endPtr := Ptr(ORD(textPtr) + textLength - 1);    { ptr to last char of text }
  8492.   endPlus1Ptr := Ptr(ORD(endPtr) + 1);    { useful to have around }
  8493.   
  8494.   { go to start of first word }
  8495.   ScanToNonBreak(textPtr,endPtr,wordPtr);
  8496.   
  8497.   IF wordPtr = endPlus1Ptr THEN GOTO 9;    { there is no first word }
  8498.   
  8499.   wordCount := 1;
  8500.   
  8501.   WHILE TRUE DO    { repeat forever, sort of }
  8502.     BEGIN
  8503.       { we come in at the start of a word; let's get to its end }
  8504.       ScanToBreak(wordPtr,endPtr,breakPtr);
  8505.       
  8506.       { now, is it the right word? }
  8507.       IF wordCount = wordIndex THEN
  8508.         BEGIN
  8509.           { yes }
  8510.           wordOffset := ORD(wordPtr) - ORD(textPtr);
  8511.           wordLength := ORD(breakPtr) - ORD(wordPtr);
  8512.           myErr := noErr;
  8513.           GOTO 9;
  8514.         END;
  8515.         
  8516.       { not the right word, try the next }
  8517.       ScanToNonBreak(breakPtr,endPtr,wordPtr);    { this works even if breakPtr = endPtr + 1 }
  8518.       IF wordPtr = endPlus1Ptr THEN GOTO 9;    { no next word }
  8519.       
  8520.       { we're at the start of the next word }
  8521.       wordCount := wordCount+1;
  8522.     END;    { of WHILE loop }
  8523.     
  8524. 9:    { finish up }
  8525.   MyGetWord := myErr;
  8526. END;    { MyGetWord }
  8527.  
  8528. {$S QuillNew}
  8529. FUNCTION MyGetUniformStyles(theTE: TEHandle; VAR onStyles: Style; VAR offStyles: Style): OSErr;
  8530. { put each style item that is on across the whole selection
  8531.   into onStyles, each style item that is off across the
  8532.   whole selection into offStyles.  The selection is mixed
  8533.   respect to those style items that don't show up in
  8534.   onStyles or offStyles.
  8535.   INPUT:    theTE        handle to the TE record
  8536.               onStyles    return VAR for subset of style items ON
  8537.                         for whole selection
  8538.               offStyles    return VAR for subset of style items OFF
  8539.                         for whole selection
  8540.   OUTPUT:    error code (noErr if none)
  8541.   NOTES:    (1) if this routine is working right, then the intersection
  8542.               of onStyles and offStyles should be empty
  8543.             (2) we don't really need to lock handles, since we're only
  8544.             acessing fields, but it makes me feel better
  8545.             (3)  **CHECK how this does with 0-length selections
  8546.             (4) there don't seem to be any error conditions . . . .
  8547.             (maybe NIL myStylRuns should be an error, since it can
  8548.             happen for several reasons - and may mean something in
  8549.             the future as well)
  8550.             (5) using GetStylScrap seems more stable than walking
  8551.             the TEStyleHandle (and associated data structures) myself;
  8552.             it's also (a) easier and (b) less efficient
  8553. }
  8554. LABEL 9;
  8555. VAR myErr:            OSErr;
  8556.     notOffStyles:    Style;
  8557.     myStylRuns:        StScrpHandle;
  8558.     i:                INTEGER;
  8559.     runStyle:        Style;
  8560. BEGIN
  8561.   myErr := noErr;
  8562.   onStyles := gAllStyles;
  8563.   { we'll whittle that down later }
  8564.   notOffStyles := [];    { and build this up }
  8565.   
  8566.   myStylRuns := GetStylScrap(theTE);
  8567.   
  8568.   IF myStylRuns = NIL THEN
  8569.     BEGIN
  8570.       { old-style TERecord - everything's uniform }
  8571.       { **CHECK - how about memory or other errors? }
  8572.       onStyles := theTE^^.txFace;
  8573.       notOffStyles := onStyles;
  8574.       myErr := noErr;
  8575.       GOTO 9;
  8576.     END;
  8577.     
  8578.   HLock(Handle(myStylRuns));
  8579.   
  8580.   WITH myStylRuns^^ DO
  8581.     BEGIN
  8582.       FOR i := 0 TO (scrpNStyles - 1) DO
  8583.         BEGIN
  8584.           runStyle := scrpStyleTab[i].scrpFace;
  8585.           onStyles := onStyles * runStyle;
  8586.           notOffStyles := notOffStyles + runStyle;
  8587.         END;    { of FOR }
  8588.     END;    { of WITH myStylRuns^^ }
  8589.     
  8590.   myErr := noErr;
  8591.     
  8592. 9:    { finish up }
  8593.  
  8594.   IF myStylRuns <> NIL THEN DisposHandle(Handle(myStylRuns));
  8595.   offStyles := gAllStyles - notOffStyles;
  8596.   
  8597.   MyGetUniformStyles := myErr;
  8598. END;    { MyGetUniformStyles }
  8599.  
  8600.  
  8601. {$S QuillNew }
  8602. FUNCTION MyMakeFSSForWndw(window: WindowPtr;  VAR theFSS: FSSpec):  OSErr;
  8603. { this routine will attempt to come up with a file spec for a given window.
  8604.   Its plan of attack is:
  8605.   (1) if the window doc record has a valid FSSpec in it, then return that.
  8606.   (2) if not, then concoct an FSSpec from the window title and the default
  8607.       directory and path
  8608.   The file spec is returned in theFSS.  If the call fails, then theFSS is
  8609.   marked invalid (vRefNum = badVRefNum).
  8610.   The routine will not create the file for you, nor tell you if it already
  8611.   exists.  It also doesn't "mark" the window doc record with the resulting
  8612.   FSSpec.  You can do it yourself, if you want to.
  8613.   INPUTS:    window        ptr to the window
  8614.               theFSS        result VAR for the file spec (if the call fails, it
  8615.                         will have its vRefNum set to badVRefNum)
  8616.   OUTPUTS:    error code (noErr if none)
  8617.   ERRORS:
  8618.   SIDE EFFECTS:
  8619. }
  8620. VAR wndwTitle:    Str255;
  8621.     myErr:        OSErr;
  8622. BEGIN
  8623.   WITH DocumentPeek(window)^ DO
  8624.     BEGIN
  8625.       IF docFile.vRefNum <> badVRefNum THEN
  8626.         BEGIN
  8627.           { file spec in doc record is good }
  8628.           theFSS := docFile;
  8629.           MyMakeFSSForWndw := noErr;
  8630.           EXIT(MyMakeFSSForWndw);
  8631.         END;
  8632.     END;
  8633.     
  8634.   { file spec in doc record wasn't good - concoct one }
  8635.   GetWTitle(window,wndwTitle);
  8636.   myErr := FSMakeFSSpec(0,0,wndwTitle,theFSS);
  8637.   { note that fnfErr is ok here; it just means the file doesn't exist yet }
  8638.   IF myErr = fnfErr THEN myErr := noErr;    { so discard that error }
  8639.   IF myErr <> noErr THEN theFSS.vRefNum := badVRefNum;
  8640.   MyMakeFSSForWndw := myErr;
  8641. END;    { MyMakeFSSForWndw }
  8642.  
  8643.  
  8644. {$S QuillNew }
  8645. FUNCTION MyNewWindow(VAR window: WindowPtr): OSErr;
  8646. { create a new window document and make it the front window 
  8647.   INPUTS:    window        return VAR for ptr to new window
  8648.   OUTPUTS:    error code (noErr if none)
  8649.   SIDE EFFECTS:
  8650.   NOTES:    this is a major rewrite of DoNew for Quill.
  8651.               Some differences:
  8652.             (1) returns ptr to the window, error code
  8653.             (2) offsets new window position from front window (if any)
  8654.             (3) keeps track of total number of docs created (from app
  8655.                 startup) to make up a default name
  8656.             (4) marks new document docFile.vRefNum with badVRefNum (no valid file yet)
  8657.             (5)    and it's generally cleaner
  8658. }
  8659. LABEL 6,7,8,9;
  8660. VAR myErr:            OSErr; 
  8661.     wndwStorage:    Ptr;
  8662.     oldFront:        WindowPtr;
  8663.     destRect:        Rect;
  8664.     viewRect:        Rect;
  8665.     newTitle:        Str255;
  8666. BEGIN
  8667.   myErr := genericErr;
  8668.   window := NIL;
  8669.   
  8670.   IF gNumDocuments >= kMaxOpenDocuments THEN 
  8671.     BEGIN
  8672.       gTempBool := CatchErr(   errTooManyDocs , 20113 , myErr );
  8673.       GOTO 9;    { clean up }
  8674.     END;
  8675.   
  8676.   { get storage for new window document record }
  8677.   wndwStorage := NewPtr(SizeOf(DocumentRecord));
  8678.   IF CatchErr(   MemError , 20114 , myErr ) THEN GOTO 9;
  8679.   
  8680.   oldFront := FrontWindow;    { need this later for positioning }
  8681.   
  8682.   window := GetNewWindow(rDocWindow,wndwStorage,WindowPtr(-1));
  8683.   IF window = NIL THEN
  8684.     BEGIN
  8685.       gTempBool := CatchErr(   errNoNewWindow , 20115 , myErr );
  8686.       GOTO 8;    { call fails - must dispose of storage }
  8687.     END;
  8688.   
  8689.   { we've got a window }
  8690.   { if there was a previous front window, offset position of the new one }
  8691.   IF oldFront <> NIL THEN WITH oldFront^.portBits.bounds DO
  8692.       MoveWindow(window,45 - left,45 - top,TRUE);    { the numbers are a little funny to satisfy MoveWindow }
  8693.       
  8694.   SetPort(window);
  8695.   WITH window^, DocumentPeek(window)^ DO
  8696.     BEGIN
  8697.       { set up all the fields of the window doc }
  8698.       
  8699.       docFile.vRefNum := badVRefNum;    { no valid file yet }
  8700.       
  8701.       { set up new-style TE record }
  8702.       GetTERect(window,viewRect);
  8703.       destRect := viewRect;
  8704.       destRect.right := destRect.left + kMaxDocWidth;
  8705.       
  8706.       docTE := TEStylNew(destRect,viewRect);
  8707.       IF docTE = NIL THEN
  8708.         BEGIN
  8709.           gTempBool := CatchErr(   errNoNewTE , 20116 , myErr );
  8710.           GOTO 7;    { call fails - must close window }
  8711.         END;
  8712.       
  8713.       TEAutoView(TRUE,docTE);
  8714.       docClik := docTE^^.clikLoop;
  8715.       docTE^^.clikLoop := @AsmClikLoop;
  8716.       
  8717.       docVScroll := GetNewControl(rVScroll,window);
  8718.       IF docVScroll = NIL THEN
  8719.         BEGIN
  8720.           gTempBool := CatchErr(   errNoNewControl , 20117 , myErr );
  8721.           GOTO 6;    { call fails - must get rid of docTE }
  8722.         END;
  8723.       
  8724.       docHScroll := GetNewControl(rHScroll,window);
  8725.       IF docHScroll = NIL THEN
  8726.         BEGIN
  8727.           gTempBool := CatchErr(   errNoNewControl , 20118 , myErr );
  8728.           GOTO 6;    { call fails - must get rid of docTE }
  8729.         END;
  8730.       
  8731.       { got all the data structures we need; call will succeed }
  8732.       AdjustScrollValues(window,FALSE);
  8733.       
  8734.       { the number of currently open windows - will be decremented when we close a window }
  8735.       gNumDocuments := gNumDocuments+1;
  8736.       
  8737.       { the number of windows that have been opened since app startup - 
  8738.         used for default title; won't be decremented }
  8739.       gDocCount := gDocCount+1;
  8740.       
  8741.       newTitle := Concat('Untitled #',MyNumToStr(gDocCount));
  8742.       SetWTitle(window,newTitle);
  8743.       
  8744.       CleanWindow(window);    { windows are born clean }
  8745.       
  8746.       { we're fine - finish up }
  8747.       ShowWindow(window);
  8748.       myErr := noErr;
  8749.       GOTO 9;    { skip error handling }
  8750.       
  8751.       
  8752.       
  8753.       { call fails - error handling }
  8754.       { we'll do these two inside the WITH , because that's where they originated }
  8755.       { neatness counts }
  8756.       
  8757. 6:      { dispose of docTE }
  8758.       TEDispose(docTE);
  8759.       
  8760. 7:      { close down window }
  8761.       CloseWindow(window);
  8762.       
  8763.     END;    { of big WITH }
  8764.     
  8765.   { one last piece of error handling }
  8766. 8:    { dispose of window storage (CloseWindow doesn't do that for you) }
  8767.   DisposPtr(Ptr(window));
  8768.   
  8769. 9:    { finish up }
  8770.   MyNewWindow := myErr;
  8771. END;    { MyNewWindow }
  8772.  
  8773. {$S QuillNew}
  8774. FUNCTION MyNumToStr(theNum: LONGINT): Str255;
  8775. { function version of NumToString
  8776.   INPUTS:    theNum        number to be converted to string
  8777.   OUTPUTS:    resulting string
  8778.   ERRORS:
  8779.   SIDE EFFECTS:
  8780. }
  8781. VAR resStr:    Str255;
  8782. BEGIN
  8783.   NumToString(theNum,resStr);
  8784.   MyNumToStr := resStr;
  8785. END;    { MyNumToStr }
  8786.  
  8787. {$S QuillNew}
  8788. FUNCTION MyOpenWindow(myFSSpec: FSSpec):  OSErr;
  8789. { open a new window for the given file.  If there's
  8790.   already a window open for it, bring it to the front
  8791.   INPUTS:    myFSSpec        the file
  8792.   OUTPUTS:    error code (noErr if none)
  8793.   ERRORS:
  8794.   SIDE EFFECTS:
  8795. }
  8796. LABEL 9;
  8797. VAR myErr:    OSErr; 
  8798.     window:    WindowPtr;
  8799. BEGIN
  8800.   myErr := genericErr;
  8801.   { maybe it's already open - if it is, should we just make that the
  8802.     front window, or should we "refill it" from the file?
  8803.     (I'll just make it front, for now) }
  8804.   
  8805.   window := FrontWindow;
  8806.   WHILE window <> NIL DO
  8807.     BEGIN
  8808.       IF EqualFSSpecs(DocumentPeek(window)^.docFile,myFSSpec) THEN
  8809.         BEGIN
  8810.           SelectWindow(window);
  8811.           myErr := noErr;
  8812.           GOTO 9;    { finish up }
  8813.         END;
  8814.       window := WindowPtr(WindowPeek(window)^.nextWindow);
  8815.     END;
  8816.   
  8817.   { need a new window }
  8818.   IF CatchErr(   MyNewWindow(window) , 20313 , myErr ) THEN GOTO 9;    
  8819.   SetWTitle(window,myFSSpec.name);
  8820.   WITH DocumentPeek(window)^ DO
  8821.     BEGIN
  8822.       IF CatchErr(   FileToTERec(myFSSpec,docTE) , 20314 , myErr ) THEN GOTO 9;
  8823.       InvalRect(docTE^^.viewRect);    { **CHECK - this have to be locked? }
  8824.       docFile := myFSSpec;
  8825.     END;
  8826.     
  8827. 9:    { finish up }
  8828.   MyOpenWindow := myErr;
  8829. END;    { MyOpenWindow }
  8830.  
  8831. {$S QuillNew}
  8832. FUNCTION MySendWindow(aWindow: WindowPtr; bWindow: WindowPtr;
  8833.     whereMod: DescType): OSErr;
  8834. { move a window's place in the front-to-back ordering so that
  8835.   it is either in front of, behind, or replacing a given window
  8836.   INPUTS:    aWindow            the window to be moved
  8837.               bWindow            the "reference window" that aWindow is
  8838.                             to be moved in front of, behind, or into
  8839.             whereMod        kAEBefore, kAEAfter, or kAEReplace
  8840.   OUTPUTS:    error code (noErr if none)
  8841.   NOTES:    (1) in the "into" (replacing) case, bWindow will be eliminated
  8842.               without saving
  8843.             (2)  we might be better off with a "set window index" routine
  8844.             here (but I don't think so)
  8845.             (3)  if you're modifying this routine, see IMPORTANT NOTE below
  8846. }
  8847. LABEL 9;
  8848. VAR myErr:        OSErr;
  8849.     aIndex:        INTEGER;
  8850.     bIndex:        INTEGER;
  8851.     cIndex:        INTEGER;
  8852.     cWndw:        WindowPtr;
  8853.  
  8854.     PROCEDURE CorrectVis;
  8855.     { this makes some vis region adjustments needed when the
  8856.       the SendBehind call actually moves a window closer to
  8857.       the front.  See Inside Mac I-286.
  8858.       INPUTS:    none
  8859.       OUTPUTS:    none
  8860.       NOTES:    wholely owned by MySendWindow
  8861.     }
  8862.     VAR wPeek:    WindowPeek;
  8863.     BEGIN
  8864.       wPeek := WindowPeek(aWindow);
  8865.       PaintOne(wPeek,wPeek^.strucRgn);
  8866.       CalcVis(wPeek);
  8867.     END;    { CorrectVis }
  8868.     
  8869.     
  8870. BEGIN
  8871.   myErr := genericErr;
  8872.   
  8873.   IF (whereMod <> kAEBefore) & (whereMod <> kAEAfter) & (whereMod <> kAEReplace) THEN
  8874.     BEGIN
  8875.       myErr := errAEBadData;    { or whatever }
  8876.       GOTO 9;
  8877.     END;
  8878.     
  8879.   aIndex := IndexFromWndwPtr(aWindow);
  8880.   bIndex := IndexFromWndwPtr(bWindow);
  8881.   IF (aIndex = 0) | (bIndex = 0) THEN
  8882.     BEGIN
  8883.       { at least one of these isn't a current window }
  8884.       myErr := errAEBadData;
  8885.       GOTO 9;
  8886.     END;
  8887.     
  8888.   { IMPORTANT NOTE:                                                               }
  8889.   {  after this point in the code there is nothing that can generate an error; so }
  8890.   {  since it's convenient for the code, I'll set myErr = noErr here.  Think of   }
  8891.   {  it as the noErr result of the last test, above.  But if you change the code  }
  8892.   {  around, be careful!                                                          }
  8893.   
  8894.   myErr := noErr;
  8895.   
  8896.   IF aWindow = bWindow THEN GOTO 9;    { windows are the same, no action necessary }
  8897.     
  8898.   IF whereMod = kAEAfter THEN
  8899.     BEGIN
  8900.       IF aIndex = bIndex + 1 THEN GOTO 9;    { aWindow already right behind bWindow, save yourself the bother }
  8901.       
  8902.       { otherwise, send aWindow behind bWindow }
  8903.       SendBehind(aWindow,bWindow);
  8904.       IF aIndex > bIndex + 1 THEN CorrectVis;
  8905.       GOTO 9;
  8906.     END;
  8907.     
  8908.   IF whereMod = kAEReplace THEN
  8909.     BEGIN
  8910.       SendBehind(aWindow,bWindow);
  8911.       IF aIndex > bIndex + 1 THEN CorrectVis;
  8912.       ShutTheWindow(bWindow);
  8913.       GOTO 9;
  8914.     END;
  8915.     
  8916.   IF whereMod = kAEBefore THEN
  8917.     BEGIN
  8918.       IF aIndex = bIndex - 1 THEN GOTO 9;    { aWindow already in front of bWindow, save yourself the bother }
  8919.       
  8920.       { otherwise:  if bWindow is front, make aWindow front }
  8921.       IF bIndex = 1 THEN SelectWindow(aWindow)
  8922.       ELSE
  8923.         BEGIN
  8924.           { here's our situation:  bWindow is NOT front, so there's something }
  8925.           { in front of it - call it cWindow.  We want to put aWindow in      }
  8926.           { front of bWindow, so we'll put it just behind cWindow.  We KNOW   }
  8927.           { aWindow <> cWindow, because of the "aIndex = bIndex - 1" test     }
  8928.           { above (this was a glitch in an earlier version)                   }
  8929.  
  8930.           cIndex := bIndex - 1;
  8931.           cWndw := WndwPtrFromIndex(cIndex);
  8932.           SendBehind(aWindow,cWndw);
  8933.           IF aIndex > cIndex + 1 THEN CorrectVis;
  8934.         END;
  8935.     END;
  8936.     
  8937. 9: { finish up }
  8938.   MySendWindow := myErr;
  8939. END;    { MySendWindow }
  8940.  
  8941. {$S QuillNew}
  8942. FUNCTION MyRandom(count: LongInt): LongInt;
  8943. { return a random integer between 1 and count, inclusive
  8944.   INPUTS:    count        upper bound for random number
  8945.   OUTPUTS:    a random integer between 1 and count, inclusive
  8946.   NOTES:    **CHECK - this is a quick, dirty, and WRONG version
  8947.               to be used for testing only
  8948. }
  8949. VAR longRandom:    LongInt;
  8950. BEGIN
  8951.   longRandom := $10000*Random + Random;
  8952.   MyRandom := (ABS(longRandom) MOD count) + 1;
  8953. END;    { MyRandom }
  8954.  
  8955. {$S QuillNew }
  8956. FUNCTION MyTerminate(saveOpt: DescType; VAR userCancelled: BOOLEAN): OSErr;
  8957. { tell the event loop to quit the app by setting gQuitNow to TRUE.  
  8958.   saveOpt can be kAEYes (save all docs, don't bother user), kAENo
  8959.   (don't save), or kAEAsk (ask the user on each file).  In the 
  8960.   "ask user" case, use AEInteractWithUser before interacting.  Also
  8961.   in the "ask user" case, give the user the option to cancel each step
  8962.   of the way; if cancel, then return without quitting
  8963.   INPUTS:    saveOpt            save, don't save, or ask user
  8964.               userCancelled    result VAR, returns TRUE if user cancelled,
  8965.                             FALSE o.w.
  8966.   OUTPUTS:    error code - interaction trouble, file-and-mem trouble,
  8967.               or whatever (noErr if no error).  User cancellation is 
  8968.             NOT an error
  8969.   ERRORS;
  8970.   SIDE EFFECTS:    may bring app to front for user interaction; also 
  8971.                   gets rid of some AE data structures that are used
  8972.                 globally
  8973.   NOTES:    if the call fails, we don't quit.  In a real app we would
  8974.               want better error handling
  8975. }
  8976. LABEL 9;
  8977. VAR myErr:    OSErr;
  8978. BEGIN
  8979.   myErr := genericErr;
  8980.   userCancelled := FALSE;
  8981.   
  8982.   IF CatchErr(   SmartCloseAll(saveOpt,userCancelled) , 8313 , myErr ) THEN GOTO 9;    { set function result }
  8983.   IF userCancelled THEN 
  8984.     BEGIN
  8985.       MyTerminate := noErr;    { user cancelled - it's not an error }
  8986.       EXIT(MyTerminate);        { but don't quit app }
  8987.     END;
  8988.   
  8989.   { dispose of global gSelfAddrDesc }
  8990.   IF CatchErr(   AEDisposeDesc(gSelfAddrDesc) , 8315 , myErr ) THEN GOTO 9;
  8991.   
  8992.   { everything's fine, so tell the app to quit }
  8993.   gQuitNow := TRUE;
  8994.   myErr := noErr;
  8995.   
  8996. 9:  { set function value }
  8997.   MyTerminate := myErr;
  8998. END;    { MyTerminate }
  8999.  
  9000. {$S Main}    
  9001. FUNCTION NewPrintText( hTE : TEHandle; useDialog: BOOLEAN ): OSErr;
  9002.  
  9003. {    Prints the edit record. Opens a printer port, calculates the numbers of lines
  9004.     per page (it may be different for each page depending on the the text styles) and
  9005.     then calls TEUpdate for the page, scroll a page and TEUpdate, etc. }
  9006. { CHANGES FOR QUILL:  added useDialog parameter, gotPrintRec variable;
  9007.   routine now skips print dialog and uses default print record if useDialog is FALSE
  9008.   
  9009.   01/28/92    BHM        Renamed NewPrintText; now returns OSErr, including "user cancelled"
  9010.                       **CHECK - I squeezed in "user cancelled" check, but it's just a band-aid;
  9011.                     this routine should be rewritten
  9012. }
  9013.  
  9014. CONST
  9015.     Margins                = 20;         { page margins }
  9016.     
  9017. VAR gotPrintRec:        BOOLEAN;
  9018.     totalLines:            INTEGER;    { number of lines in text }
  9019.     rView:                Rect;        { viewRect for TERect }
  9020.     oldPort:            grafPtr;    { hold original grafPtr }
  9021.     oldView:            Rect;        { hold original viewRect }
  9022.     oldDest:            Rect;        { hold original destRect }
  9023.     totalHeight:        INTEGER;    { lineHeight for TERec }
  9024.     currentLine:        INTEGER;    { what line are we on }
  9025.     scrollAmount:        INTEGER;    { how much we scroll by }
  9026.     zeroRect:            Rect;        { 0,0,0,0 rect used in clipRect }
  9027.     
  9028.     thePrinterStatus:    TPrStatus; { printer status }
  9029.     openPrintManager:    BOOLEAN;    { flag if print manager can be opened okay }
  9030.     abort:                BOOLEAN;    { flag if cmd-period is hit to exit routine }
  9031.     viewHeight:            INTEGER;    { temp that has the viewRect height+1 to test conditions }
  9032.  
  9033.     
  9034. BEGIN { NewPrintText }
  9035.     openPrintManager := FALSE; {printer not open yet}
  9036.     IF gPrinterRecord <> NIL THEN BEGIN { do we have a legitimate record?}
  9037.         PrOpen; {open mr. print record if okay}
  9038.         
  9039.         IF useDialog THEN gotPrintRec := PrJobDialog(gPrinterRecord)    { bring up print dialog }
  9040.         ELSE
  9041.           BEGIN    { use defaults }
  9042.             PrintDefault(gPrinterRecord);
  9043.             gotPrintRec := TRUE;
  9044.           END;
  9045.           
  9046.           { here's where it's tossed in }
  9047.           IF gotPrintRec THEN NewPrintText := noErr ELSE NewPrintText := errAEUserCancelled;
  9048.           
  9049.             
  9050.         IF gotPrintRec THEN BEGIN {bring up job dialog}
  9051.             GetPort( oldPort ); { save the old stuff to restore later }
  9052.             oldView := hTE^^.viewRect; 
  9053.             oldDest := hTE^^.destRect;
  9054.             gPrinterPort := PrOpenDoc( gPrinterRecord, NIL, NIL );
  9055.             OpenPrintManager := ( PrError = noErr );
  9056.         END; { if }
  9057.     END; { if }
  9058.  
  9059.     IF OpenPrintManager THEN BEGIN
  9060.         SetPort( grafPtr( gPrinterPort ) ); { printer port is now the current port }
  9061.         SetRect( zeroRect, 0, 0, 0, 0 );
  9062.  
  9063.         rView := gPrinterRecord^^.PrInfo.rPage; { get the size of the page rectangle }
  9064.         InsetRect( rView, Margins, Margins );  { adjust it for the margins }
  9065.         hTE^^.inPort := GrafPtr( gPrinterPort ); { force TE to look at the printer port }
  9066.         hTE^^.destRect := rView;
  9067.         hTE^^.viewRect := rView; { set new view and dest rects to the TERec }
  9068.         TECalText( hTE ); { recalculate our lineStarts array with the new rects }
  9069.         totalLines := hTE^^.nLines; { get the number of lines in the newly sized TERec }
  9070.         totalHeight := TEGetHeight( totalLines, 0, hTE );
  9071.         hTE^^.destRect.bottom := hTE^^.destRect.top + totalHeight; { how tall our destRect is }
  9072.         
  9073.         abort := FALSE;
  9074.         currentLine := 1; { TextEdit sez that TEGetHeight is 1 not 0 based }
  9075.         
  9076.         WHILE ( NOT ( abort ) AND ( currentLine <= totalLines ) ) DO BEGIN
  9077.             PrOpenPage( gPrinterPort, NIL );
  9078.             scrollAmount := 0;
  9079.             ClipRect( gPrinterRecord^^.PrInfo.rPage ); { Open clipping so text will be drawn }
  9080.             
  9081.             viewHeight := hTE^^.viewRect.bottom - hTE^^.viewRect.top + 1;
  9082.  
  9083.             { figure out how many lines there are per page }
  9084.             WHILE ((( scrollAmount + TEGetHeight( currentLine, currentLine, hTE ) ) <= viewHeight )
  9085.                 AND ( currentLine <= totalLines ) )  DO BEGIN
  9086.                 scrollAmount := scrollAmount + TEGetHeight( currentLine, currentLine, hTE );
  9087.                 currentLine := currentLine + 1;
  9088.             END; { while }
  9089.             
  9090.             hTE^^.viewRect.bottom := scrollAmount + Margins; { Add margins since top has a margin }
  9091.             TEDeactivate( hTE ); { Deactive the edit record so we don't print the cursor or selection range }
  9092.             TEUpdate( hTE^^.viewRect, hTE ); { print the page }
  9093.             ClipRect( zeroRect ); { Close clipping so that TEScroll doesn't redraw the text }
  9094.             TEScroll( 0, -scrollAmount, hTE ); { scroll the page so we can print the next one }
  9095.             hTE^^.viewRect.bottom := rView.bottom; { reset bottom to full page }
  9096.     
  9097.             IF prError = iPrAbort THEN 
  9098.                 abort := TRUE;
  9099.             PrClosePage( gPrinterPort ); { close everything up }
  9100.         END; { while }
  9101.  
  9102.         PrCloseDoc( gPrinterPort );
  9103.         IF ( gPrinterRecord^^.prJob.bJDocLoop = bSpoolLoop ) AND ( PrError = noErr ) THEN
  9104.             PrPicFile( gPrinterRecord, NIL, NIL, NIL, thePrinterStatus );
  9105.         PrClose;
  9106.         SetPort( oldPort );
  9107.         hTE^^.inPort := oldPort;
  9108.         hTE^^.viewRect := oldView; { restore the old stuff when we are done }
  9109.         hTE^^.destRect := oldDest;
  9110.         TEUpdate( hTE^^.viewRect, hTE ); { update everything after resetting the port }
  9111.     END; { if }
  9112. END; { NewPrintText }
  9113.  
  9114. {$S QuillNew}
  9115. PROCEDURE PostHandler(reply: AppleEvent; errNum: OSErr);
  9116. { this routine is called at the end of every AppleEvent
  9117.   handler, to do any generic stuff we might want done there.
  9118.   Right now all it does is set the gInHandler flag, so utility
  9119.   routines (most particularly, error-reporting routines) can
  9120.   always know if we're in a handler or not
  9121.   INPUTS:    reply        the reply AppleEvent in which the handler
  9122.                           should return any error parameters; may be
  9123.                         typeNull if the sender didn't ask for a reply
  9124.             myErr        the error code generated by the handler (may be noErr)
  9125.   OUTPUTS:    none
  9126.   NOTES:    this may go away in the near future
  9127.               09/19/91    BHM        Added gErrorDesc stuff
  9128.             **CHECK - QUESTION - how should we deal with errors in here?
  9129. }
  9130. VAR errDescExists:    BOOLEAN;
  9131. BEGIN
  9132.   gInHandler := FALSE;
  9133.   
  9134.   errDescExists := (gErrorDesc.descriptorType <> typeNull);
  9135.   
  9136.   IF (reply.descriptorType <> typeNull) & (errNum <> noErr) & errDescExists THEN
  9137.       { they want a reply; there was an error; there's an object in gErrorDesc - }
  9138.       { so send it back with the reply                                           }
  9139.       gTempBool := CheckErr(   AEPutParamDesc(reply,keyAEErrorObject,gErrorDesc) , 21313 );
  9140.       
  9141.   { in any case, if there is a gErrorDesc, now's a good time to get rid of it }
  9142.   IF errDescExists THEN
  9143.     BEGIN
  9144.       gTempBool := CheckErr(   AEDisposeDesc(gErrorDesc) , 21314 );
  9145.       gErrorDesc := gNullDesc;    { just for neatness }
  9146.     END;
  9147. END;    { PostHandler }
  9148.  
  9149. {$S QuillNew}
  9150. PROCEDURE PreHandler;
  9151. { this routine is called at the start of every AppleEvent
  9152.   handler, to do any generic stuff we might want done there.
  9153.   Right now all it does is set the gInHandler flag, so utility
  9154.   routines (most particularly, error-reporting routines) can
  9155.   always know if we're in a handler or not
  9156.   INPUTS:    none
  9157.   OUTPUTS:    none
  9158.   NOTES:    this may go away in the near future
  9159.               09/18/91    BHM        Added gErrorDesc init (in case a handler doesn't use AEResolve,
  9160.                                 this will make sure we don't get a spurious, left-over error)
  9161. }
  9162. BEGIN
  9163.   gInHandler := TRUE;
  9164.   gErrorDesc := gNullDesc;
  9165. END;    { PreHandler }
  9166.  
  9167. {$S QuillNew2}
  9168. FUNCTION PrintFile(myFSS: FSSpec): OSErr;
  9169. { print the text fram a specified file.  We use the trick of opening
  9170.   a TERec somewhere off the screen, printing it, and throwing it away.
  9171.   
  9172.   Interaction (i.e., the Print Dialog) is determined by some
  9173.   globals, gInterMode and gTriedDialog, originally set by 
  9174.   HandlePrint.  If gInterMode is kAENeverInteract or kAECanInteract,
  9175.   skip the Print Dialog and use default print rec values.  If
  9176.   gInterMode is kAEAlwaysInteract, then look at gTriedDialog to see
  9177.   if we've already tried the dialog once for this Print event.  (Even
  9178.   if we have a list of tokens, we only want to do the dialog once.)
  9179.   If gTriedDialog is TRUE, then skip the dialog.  If it's FALSE, set
  9180.   it to TRUE and try the dialog (and if you can't interact, return an
  9181.   error).  In any case, don't try the dialog until you're sure you
  9182.   have something to print.
  9183.   
  9184.   INPUTS:    myFSS        file spec for file to be printed
  9185.   OUTPUTS:    error code (noErr if none).  "user cancelled" is an error.
  9186.   SIDE EFFECTS:    may change gTriedDialog
  9187.   NOTES:    it's NewPrintText that actually puts up the dialog, if needed;
  9188.               we just call NewPrintText
  9189. }
  9190. LABEL 9;
  9191. VAR myErr:        OSErr;
  9192.     teHndl:        TEHandle;
  9193.     destRect:    Rect;
  9194.     useDialog:    BOOLEAN;
  9195. BEGIN
  9196.   myErr := genericErr;
  9197.   teHndl := NIL;
  9198.   
  9199.   SetRect(destRect,-500,-500,0,0);    { set it offscreen - **CHECK this technique }
  9200.   teHndl := TEStylNew(destRect,destRect);
  9201.   IF teHndl = NIL THEN
  9202.     BEGIN
  9203.       gTempBool := CatchErr(   errNoNewTE , 1813 , myErr );    { *CHECK better error code - probably a mem error }
  9204.       GOTO 9;
  9205.     END;
  9206.     
  9207.   { got a valid TERec, read the file into it }
  9208.   IF CatchErr(   FileToTERec(myFSS,teHndl) , 1814 , myErr ) THEN GOTO 9;
  9209.   
  9210.   { now - take care of interaction }
  9211.   useDialog := ((gInterMode = kAEAlwaysInteract) | (gInterMode = kAECanInteract)) & (NOT gTriedDialog);
  9212.   IF useDialog THEN
  9213.     BEGIN
  9214.       { should try to use the dialog }
  9215.       gTriedDialog := TRUE;    { well, nothing can stop me from TRYING to interact now }
  9216.       IF CatchErr(   AEInteractWithUser(kNoTimeOut,NIL,NIL) , 1815 , myErr ) THEN GOTO 9;
  9217.     END;
  9218.     
  9219.   { if we get here, then we either don't need to interact, or we can }
  9220.   gTempBool := CatchErr(   NewPrintText(teHndl,useDialog) , 24214 , myErr );
  9221.   
  9222. 9:
  9223.   IF teHndl <> NIL THEN TEDispose(teHndl);
  9224.   
  9225.   PrintFile := myErr;
  9226. END;    { PrintFile }
  9227.  
  9228.  
  9229. {$S QuillNew2}
  9230. FUNCTION PrintFileList(theList: AEDesc): OSErr;
  9231. { given a list of files - or, at least, things that can be
  9232.   coerced to files - print them all.
  9233.   
  9234.   Interaction (i.e., the Print Dialog) is handled by PrintFile;
  9235.   it depends on the globals gInterMode and gTriedDialog, which 
  9236.   must be set (usually by HandlePrint) before this routine is
  9237.   called.
  9238.   
  9239.   INPUTS:    theList        list of files to be printed
  9240.   OUTPUTS:    error code (noErr if none)
  9241. }
  9242. LABEL 9;
  9243. VAR myErr:        OSErr;
  9244.     itemCount:    LongInt;
  9245.     i:            LongInt;
  9246.     myFSS:        FSSpec;
  9247. BEGIN
  9248.   myErr := genericErr;
  9249.   
  9250.   { count the items }
  9251.   IF CatchErr(   AECountItems(theList,itemCount) , 24113 , myErr ) THEN GOTO 9;
  9252.   IF itemCount = 0 THEN GOTO 9;    { empty list, we're done }
  9253.   
  9254.   { loop through the items }
  9255.   FOR i := 1 TO itemCount DO
  9256.     BEGIN
  9257.       { get the item as a file }
  9258.       IF CatchErr(   AEGetNthPtr(theList,i,typeFSS,gReturnedKeywd,gReturnedType,@myFSS,
  9259.           SizeOf(myFSS),gActSize) , 24114 , myErr ) THEN GOTO 9;
  9260.           
  9261.       { print it }
  9262.       IF CatchErr(   PrintFile(myFSS) , 24115 , myErr ) THEN GOTO 9;
  9263.     END;    { of loop }
  9264.     
  9265. 9:
  9266.   PrintFileList := myErr;
  9267. END;    { PrintFileList }
  9268.  
  9269. {$S QuillNew2}
  9270. FUNCTION PrintToken(theToken: AEDesc): OSErr;
  9271. { given a token, print the object it represents.  Right now
  9272.   we only print windows or documents (files are handled by
  9273.   PrintFile).
  9274.   
  9275.   Interaction (i.e., the Print Dialog) is determined by some
  9276.   globals, gInterMode and gTriedDialog, originally set by 
  9277.   HandlePrint.  If gInterMode is kAENeverInteract or kAECanInteract,
  9278.   skip the Print Dialog and use default print rec values.  If
  9279.   gInterMode is kAEAlwaysInteract, then look at gTriedDialog to see
  9280.   if we've already tried the dialog once for this Print event.  (Even
  9281.   if we have a list of tokens, we only want to do the dialog once.)
  9282.   If gTriedDialog is TRUE, then skip the dialog.  If it's FALSE, set
  9283.   it to TRUE and try the dialog (and if you can't interact, return an
  9284.   error).  In any case, don't try the dialog until you're sure you
  9285.   have something to print.
  9286.   
  9287.   INPUTS:    theToken        token for object to be printed; should be
  9288.                               window or document (or coercible to that)
  9289.   OUTPUTS:    error code (noErr if none).  "user cancelled" is treated 
  9290.               as an error.
  9291.   SIDE EFFECTS:    may change gTriedDialog
  9292.   NOTES:    it's NewPrintText that actually puts up the dialog, if needed;
  9293.               we just call NewPrintText
  9294. }
  9295. LABEL 9;
  9296. VAR myErr:        OSErr;
  9297.     myWndw:        WindowPtr;
  9298.     useDialog:    BOOLEAN;
  9299. BEGIN
  9300.   myErr := genericErr;
  9301.   
  9302.   { get the window - docs will coerce to windows }
  9303.   IF CatchErr(   MyAECoerceDescPtr(theToken,typeMyWndw,@myWndw,SizeOf(myWndw),gActSize) , 
  9304.       24213 , myErr ) THEN GOTO 9;
  9305.   
  9306.   { figure out the dialog stuff }
  9307.   useDialog := (gInterMode = kAEAlwaysInteract) & (NOT gTriedDialog);
  9308.   IF useDialog THEN
  9309.     BEGIN
  9310.       { should try to use the dialog - set up to interact }
  9311.       gTriedDialog := TRUE;    { well, nothing can stop me from TRYING to interact now }
  9312.       IF CatchErr(   AEInteractWithUser(kNoTimeOut,NIL,NIL) , 24214 , myErr ) THEN GOTO 9;
  9313.     END;
  9314.     
  9315.   { if we get here, then we either don't need to interact, or we can }
  9316.   gTempBool := CatchErr(   NewPrintText(DocumentPeek(myWndw)^.docTE,useDialog) , 24215 , myErr );
  9317.   
  9318. 9:
  9319.   PrintToken := myErr;
  9320. END;    { PrintToken }
  9321.  
  9322.  
  9323. {$S QuillNew2}
  9324. FUNCTION PrintTokenList(theList: AEDesc): OSErr;
  9325. { this routine takes a list of tokens (we permit embedded lists,
  9326.   but the ultimate nodes must be tokens) and prints everything in
  9327.   it.
  9328.   
  9329.   Interaction (i.e., the Print Dialog) is handled by PrintToken;
  9330.   it depends on the globals gInterMode and gTriedDialog, which 
  9331.   must be set (usually by HandlePrint) before this routine is
  9332.   called.
  9333.   
  9334.   INPUTS:    theList        list of tokens to be printed
  9335.   OUTPUTS:    error code (noErr if none)
  9336. }
  9337. LABEL 9;
  9338. VAR myErr:        OSErr;
  9339.     itemCount:    LongInt;
  9340.     i:            LongInt;
  9341.     thisItem:    AEDesc;
  9342. BEGIN
  9343.   myErr := genericErr;
  9344.   thisItem := gNullDesc;
  9345.   
  9346.   { count the items }
  9347.   IF CatchErr(   AECountItems(theList,itemCount) , 24313 , myErr ) THEN GOTO 9;
  9348.   IF itemCount = 0 THEN GOTO 9;    { empty list, we're done }
  9349.   
  9350.   { loop through the items }
  9351.   FOR i := 1 TO itemCount DO
  9352.     BEGIN
  9353.       { get the item }
  9354.       IF CatchErr(   AEGetNthDesc(theList,i,typeWildCard,gReturnedKeywd,thisItem) , 
  9355.           24114 , myErr ) THEN GOTO 9;
  9356.           
  9357.       { if it's a list, call yourself recursively }
  9358.       IF thisItem.descriptorType = typeAEList THEN
  9359.         BEGIN
  9360.           IF CatchErr(   PrintTokenList(thisItem) , 24314 , myErr ) THEN GOTO 9;
  9361.         END
  9362.       ELSE
  9363.         BEGIN
  9364.           { not a list, must be a token - print it }
  9365.           IF CatchErr(   PrintToken(thisItem) , 24315 , myErr ) THEN GOTO 9;
  9366.         END;
  9367.         
  9368.       { dispose of item for next pass }
  9369.       gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 24316 );
  9370.       thisItem := gNullDesc;
  9371.     END;    { of loop }
  9372.     
  9373. 9:
  9374.   gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 24317 );
  9375.   
  9376.   PrintTokenList := myErr;
  9377. END;    { PrintTokenList }
  9378.  
  9379.  
  9380.  
  9381. {$S QuillNew}
  9382. FUNCTION PropFromAppAccessor(wantClass: DescType; container: AEDesc ;
  9383.     containerClass: DescType; form: DescType; selectionData: AEDesc; VAR value: AEDesc;
  9384.     theRefCon: LongInt): OSErr;
  9385. LABEL 9;
  9386. VAR myErr:    OSErr;
  9387.     myProp:    DescType;
  9388. BEGIN
  9389.   myErr := accessorErr;
  9390.   value := gNullDesc;
  9391.   
  9392.   { the container should be typeNull }
  9393.   IF containerClass <> cNull THEN
  9394.     BEGIN
  9395.       gTempBool := CatchErr(   errAEWrongDataType , 18513 , myErr );
  9396.       GOTO 9;
  9397.     END;
  9398.       
  9399.   { get the property }
  9400.   IF CatchErr(   MyAECoerceDescPtr(selectionData,typeType,@myProp,SizeOf(myProp),gActSize) , 
  9401.       18515 , myErr ) THEN GOTO 9;
  9402.       
  9403.   { make the token }
  9404.   gTempBool := CatchErr(   AECreateDesc(typeMyAppProp,@myProp,SizeOf(myProp),value) , 18516 , 
  9405.       myErr );
  9406.       
  9407. 9:    { finish up }
  9408.   PropFromAppAccessor := myErr;
  9409. END;    { PropFromAppAccessor }
  9410.  
  9411. {$S QuillNew}
  9412. FUNCTION PropFromTextAccessor(wantClass: DescType; container: AEDesc ;
  9413.     containerClass: DescType; form: DescType; selectionData: AEDesc; VAR value: AEDesc;
  9414.     theRefCon: LongInt): OSErr;
  9415. LABEL 9;
  9416. VAR myErr:        OSErr;
  9417.     myText:        TextToken;
  9418.     myTextProp:    TextPropToken;
  9419.     myProp:        DescType;
  9420. BEGIN
  9421.   myErr := accessorErr;    { or whatever }
  9422.   value := gNullDesc;
  9423.   
  9424.   { check a few necessities }
  9425.   IF (wantClass <> cProperty) | (form <> formPropertyID) THEN
  9426.     BEGIN
  9427.       gTempBool := CatchErr(   errAEWrongDataType , 16113 , myErr );
  9428.       GOTO 9;    { finish up }
  9429.     END;
  9430.     
  9431.   { get the text token }
  9432.   IF CatchErr(   MyAECoerceDescPtr(container,typeMyText,@myText,SizeOf(myText),gActSize) , 
  9433.       16114 , myErr ) THEN GOTO 9;
  9434.       
  9435.   { get the property }
  9436.   IF CatchErr(   MyAECoerceDescPtr(selectionData,typeType,@myProp,SizeOf(myProp),gActSize) , 
  9437.       16115 , myErr ) THEN GOTO 9;
  9438.       
  9439.   { make the token }
  9440.   WITH myTextProp DO
  9441.     BEGIN
  9442.       tpText := myText;
  9443.       tpProp := myProp;
  9444.     END;
  9445.     
  9446.   gTempBool := CatchErr(   AECreateDesc(typeMyTextProp,@myTextProp,SizeOf(myTextProp),value) ,
  9447.       16116 , myErr );
  9448.       
  9449. 9:    { finish up }
  9450.   PropFromTextAccessor := myErr;
  9451. END;    { PropFromTextAccessor }
  9452.  
  9453.  
  9454. {$S QuillNew}
  9455. FUNCTION PropFromWndwAccessor(wantClass: DescType; container: AEDesc;
  9456.     containerClass: DescType; form: DescType; selectionData: AEDesc; VAR value: AEDesc;
  9457.     theRefCon: LongInt): OSErr;
  9458. {    NOTES:
  9459.     02/17/92    BHM        replaced pText with pContents
  9460. }
  9461. LABEL 9;
  9462. VAR myErr:        OSErr;
  9463.     window:        WindowPtr;
  9464.     myProp:        DescType;
  9465.     myText:        TextToken;
  9466.     wndwProp:    WndwPropToken;
  9467. BEGIN
  9468.   myErr := accessorErr;    { or whatever }
  9469.   value := gNullDesc;
  9470.   
  9471.   { check a few necessities }
  9472.   IF (wantClass <> cProperty) | (form <> formPropertyID) THEN
  9473.     BEGIN
  9474.       gTempBool := CatchErr(   errAEWrongDataType , 14513 , myErr );
  9475.       GOTO 9;    { finish up }
  9476.     END;
  9477.   
  9478.   { get the window }
  9479.   IF CatchErr(   MyAECoerceDescPtr(container,typeMyWndw,@window,SizeOf(window),gActSize) , 
  9480.       14514 , myErr ) THEN GOTO 9;
  9481.       
  9482.   { get the property }
  9483.   IF CatchErr(   MyAECoerceDescPtr(selectionData,typeType,@myProp,SizeOf(myProp),gActSize) , 
  9484.       14115 , myErr ) THEN GOTO 9;
  9485.       
  9486.   { EXPERIMENTAL:  special-case pContents; instead of returning a window prop token, return }
  9487.   { a text token.  This will net us all the text properties/behaviors for free - **CHECK    }
  9488.   
  9489.   IF myProp = pContents THEN
  9490.     BEGIN
  9491.       MakeTextTokenForWndw(window,myText);
  9492.       gTempBool := CatchErr(   AECreateDesc(typeMyText,@myText,SizeOf(myText),value) , 14116 , myErr );
  9493.       GOTO 9;
  9494.     END;
  9495.     
  9496.   { if it's not pContents, then just build a window prop token }
  9497.   WITH wndwProp DO
  9498.     BEGIN
  9499.       wpWndw := window;
  9500.       wpProp := myProp;
  9501.     END;
  9502.     
  9503.   gTempBool := CatchErr(   AECreateDesc(typeMyWndwProp,@wndwProp,SizeOf(wndwProp),value) , 14117 , myErr );
  9504.  
  9505. 9:
  9506.   PropFromWndwAccessor := myErr;
  9507. END;    { PropFromWndwAccessor }
  9508.  
  9509. {$S QuillNew}
  9510. FUNCTION QuietCatchErr(theErr: OSErr; VAR holdErr: OSErr): BOOLEAN;
  9511. { this routine returns TRUE if theErr is a real error (not
  9512.   noErr), FALSE if noErr.  In either case it stuffs theErr
  9513.   into the VAR parameter holdErr for later use, which can
  9514.   be particularly handy if the first parameter is an error-
  9515.   generating function (like all the AE calls).  Unlike
  9516.   CatchErr, QuietCatchErr does not put up an error alert.
  9517.   INPUTS:    theErr        potential error to be checked
  9518.               holdERR        result VAR to save the error code in
  9519.   OUTPUTS:    TRUE if theErr is a real error, FALSE if it's noErr
  9520. }
  9521. BEGIN
  9522.   holdErr := theErr;
  9523.   QuietCatchErr := (theErr <> noErr);
  9524. END;    { QuietCatchErr }
  9525.  
  9526. {$S QuillNew}
  9527. FUNCTION RealCountProc(desiredType: DescType; container: AEDesc;
  9528.     VAR result: LongInt): OSErr;
  9529. { so far all I count is:
  9530.   (1) the number of active windows in the app;
  9531.   (2) the number of chars/words/lines/items in a window or some text
  9532.   In MyCountProc, I noticed that I wasn't really using the containerClass
  9533.   parameter, and it turned out to be handy to have a version that didn't
  9534.   call for that parameter.
  9535.   
  9536.   08/21/91    BHM        put in number of list elements in a list
  9537. }
  9538. LABEL 9;
  9539. VAR myErr:    OSErr;
  9540.     myList:    AEDesc;
  9541.     window:    WindowPtr;
  9542.     myText:    TextToken;
  9543. BEGIN
  9544.   myErr := genericErr;
  9545.   result := -1;    { easily recognized illegal value }
  9546.   myList := gNullDesc;
  9547.   
  9548.   IF desiredType = cListElem THEN
  9549.     BEGIN
  9550.       { coerce the container to a list }
  9551.       IF CatchErr(   AECoerceDesc(container,typeAEList,myList) , 18216 , myErr )
  9552.           THEN GOTO 9;
  9553.       { and count its elements }
  9554.       gTempBool := CatchErr(   AECountItems(myList,result) , 18215 , myErr );
  9555.       GOTO 9;
  9556.     END;    { typeAEList }
  9557.   
  9558.   { **CHECK the next step - should we just check descriptorType directly? }
  9559.   IF MyAECoerceDescPtr(container,typeNull,@gTempLong,0,gActSize) = noErr THEN 
  9560.     BEGIN
  9561.       { container is null }
  9562.       IF (desiredType <> cWindow) & (desiredType <> cDocument) THEN myErr := errAEWrongDataType
  9563.       ELSE
  9564.         BEGIN
  9565.           { windows out of app }
  9566.           result := CountWindows;
  9567.           myErr := noErr;
  9568.         END;
  9569.       GOTO 9;    { finish up }
  9570.     END;    { cNull container }
  9571.  
  9572.   { container wasn't null; let's try to get it as a text token }
  9573.   
  9574.   { start with a window }
  9575.   IF MyAECoerceDescPtr(container,typeMyWndw,@window,SizeOf(window),gActSize) = noErr
  9576.       THEN MakeTextTokenForWndw(window,myText)
  9577.   ELSE IF MyAECoerceDescPtr(container,typeMyText,@myText,SizeOf(myText),gActSize ) <> noErr
  9578.   THEN 
  9579.     BEGIN
  9580.       { can't get a text token, nothing we can count }
  9581.       gTempBool := CatchErr(   errAEWrongDataType , 18213 , myErr );
  9582.       GOTO 9;
  9583.     END;
  9584.     
  9585.   { now we've got a text token; we can count any of the classes of text elements in it }
  9586.   { if desiredType is not a class of text elements, CountTextElems will pick up the error }
  9587.   gTempBool := CatchErr(   CountTextElems(myText,desiredType,result) , 18214 , myErr );
  9588.   
  9589. 9:    { finish up }
  9590.   gTempBool := CheckErr(   AEDisposeDesc(myList) , 18217 );
  9591.  
  9592.   RealCountProc := myErr;
  9593. END;    { RealCountProc }
  9594.  
  9595. {$S QuillNew2}
  9596. PROCEDURE ResetKeyBuffer;
  9597. { this routine resizes the key buffer to its minimum size and
  9598.   sets up various values in it
  9599.   INPUTS:    none
  9600.   OUPUTS:    none
  9601. 10/03/91    BHM        added bufDesc}
  9602. BEGIN
  9603.   SetHandleSize(Handle(keyBuffer.bufChars),kBufStartSize);    { never a grow, so should never fail }
  9604.   keyBuffer.bufSize := kBufStartSize;
  9605.   gTempBool := CheckErr(   AEDisposeDesc(keyBuffer.bufDesc) , 21913 );
  9606.   InitKeyBufVals;
  9607. END; { ResetKeyBuffer }
  9608.  
  9609.  
  9610. {$S QuillNew}
  9611. PROCEDURE ScanToBreak(startPtr: Ptr; endPtr: Ptr; VAR breakPtr: Ptr);
  9612. { starting at startPtr, scan characters until you find a word break
  9613.   character, and return a ptr to it.  If you get past endPtr and still
  9614.   haven't found it, return a ptr to 1 byte beyond endPtr.
  9615.   This is a fairly dumb version, in which the only break characters
  9616.   are spaces and carriage returns.
  9617.   INPUTS:    startPtr    ptr to first char of text to be scanned
  9618.               endPtr        ptr to last char of text to be scanned
  9619.             breakPtr    return VAR for ptr to break character
  9620.   OUTPUTS:    none
  9621.   NOTES:    (1) if startPtr is pointing to a break character,
  9622.               that's fine; just return it in breakPtr
  9623.             (2) a 0-length text is passed into this routine with 
  9624.             endPtr = startPtr - 1; in this case the routine will
  9625.             return endPtr + 1 ( = startPtr), since it can't find
  9626.             a break character among the 0 characters available for
  9627.             scanning
  9628. }
  9629. BEGIN
  9630.   breakPtr := startPtr;
  9631.   WHILE ORD(breakPtr) <> ORD(endPtr) + 1 DO
  9632.     BEGIN
  9633.       IF (breakPtr^ = asciiSpace) | (breakPtr^ = asciiCR) THEN EXIT(ScanToBreak);    { found it }
  9634.       breakPtr := Ptr(ORD(breakPtr) + 1);    { didn't find it, try next }
  9635.     END;
  9636. END;    { ScanToBreak }
  9637.  
  9638. {$S QuillNew}
  9639. PROCEDURE ScanToDelimiter(startPtr: Ptr; endPtr: Ptr; delChar: SignedByte;
  9640.     VAR delPtr: Ptr);
  9641. { starting at startPtr, scan until you find a particular dilimiting character,
  9642.   and return a ptr to it.  If you get to endPtr and still haven't found it,
  9643.   return a ptr to 1 byte beyond endPtr.  (Conceptually you can imagine a
  9644.   delimiter placed at 1 byte beyond endPtr.)
  9645.   INPUTS:    startPtr    ptr to first char of text to be scanned
  9646.               endPtr        ptr to last char of text to be scanned
  9647.             delChar        character to be scanned for
  9648.             delPtr        return VAR for ptr to delimiter
  9649.   OUTPUTS:    none
  9650.   NOTES:    (1) if startPtr is pointing to a delimiter character,
  9651.               that's fine; just return it in delPtr
  9652.             (2) a 0-length text is passed into this routine with 
  9653.             endPtr = startPtr - 1; in this case the routine will
  9654.             return endPtr + 1 ( = startPtr), since it can't find
  9655.             a delimiter character among the 0 characters available for
  9656.             scanning
  9657. }
  9658. BEGIN
  9659.   delPtr := startPtr;
  9660.   WHILE ORD(delPtr) <> ORD(endPtr)+1 DO
  9661.     BEGIN
  9662.       IF delPtr^ = delChar THEN EXIT(ScanToDelimiter);    { found it }
  9663.       delPtr := Ptr(ORD(delPtr) + 1);                        { didn't find it, try next }
  9664.     END;
  9665. END;    { ScanToDelimiter }
  9666.  
  9667. {$S QuillNew}
  9668. PROCEDURE ScanToNonBreak(startPtr: Ptr; endPtr: Ptr; VAR nbPtr: Ptr);
  9669. { starting at startPtr, scan characters until you find a non-break
  9670.   character, and return a ptr to it.  If you get past endPtr and still
  9671.   haven't found it, return a ptr to 1 byte beyond endPtr.
  9672.   This is a fairly dumb version, in which the only break characters
  9673.   are spaces and carriage returns.
  9674.   INPUTS:    startPtr    ptr to first char of text to be scanned
  9675.               endPtr        ptr to last char of text to be scanned
  9676.             breakPtr    return VAR for ptr to non-break character
  9677.   OUTPUTS:    none
  9678.   NOTES:    (1) if startPtr is pointing to a non-break character,
  9679.               that's fine; just return it in nbPtr
  9680.             (2) a 0-length text is passed into this routine with 
  9681.             endPtr = startPtr - 1; in this case the routine will
  9682.             return endPtr + 1 ( = startPtr), since it can't find
  9683.             a non-break character among the 0 characters available for
  9684.             scanning
  9685. }
  9686. BEGIN
  9687.   nbPtr := startPtr;
  9688.   WHILE ORD(nbPtr) <> ORD(endPtr) + 1 DO
  9689.     BEGIN
  9690.       IF (nbPtr^ <> asciiSpace) & (nbPtr^ <> asciiCR) THEN EXIT(ScanToNonBreak);    { found it }
  9691.       nbPtr := Ptr(ORD(nbPtr) + 1);    { didn't find it, try next }
  9692.     END;
  9693. END;    { ScanToNonBreak }
  9694.  
  9695. {$S QuillNew}
  9696. PROCEDURE SelectTextToken(theTextToken: TextToken);
  9697. { select the text represented by a token 
  9698.   INPUTS:    theTextToken        the text token . . .
  9699.   OUTPUTS:    none
  9700.   NOTES:    **CHECK - switch over to this routine throughout code 
  9701. }
  9702. BEGIN
  9703.   WITH theTextToken DO 
  9704.       TESetSelect(tokenOffset,tokenOffset + tokenLength,DocumentPeek(tokenWndw)^.docTE);
  9705. END;    { SelectTextToken }
  9706.  
  9707.  
  9708.  
  9709.  
  9710. {$S QuillNew }
  9711. PROCEDURE SendAEClose(window: WindowPtr; saveFlag, fileParamFlag: BOOLEAN;
  9712.     fileSpec: FSSpec);
  9713. { send an AppleEvent Close Event to myself, using the options and parameters
  9714.   specified.  We'll bundle up the window as an object by index
  9715.   INPUTS:    window            window to be closed
  9716.               saveFlag        TRUE if window should be saved first, FALSE o.w.
  9717.             fileParamFlag    TRUE if we're sending along a specific file spec
  9718.                             to save the window to, FALSE o.w. (if FALSE, the 
  9719.                             Close event handler will use the file in the window
  9720.                             doc record or, if there isn't one, will concoct its
  9721.                             own).  Ignored is saveFlag is FALSE
  9722.             fileSpec        spec for file to save to.  Ignored if either saveFlag
  9723.                             or fileParamFlag is FALSE
  9724.   OUTPUTS:    none
  9725.   ERRORS:
  9726.   SIDE EFFECTS:
  9727. }
  9728. LABEL 9;
  9729. VAR index:            INTEGER;
  9730.     wndwObjSpec:    AEDesc;
  9731.     myAppleEvent:    AppleEvent;
  9732.     saveOpt:        DescType;
  9733.     defReply:        AppleEvent;
  9734. BEGIN
  9735.   InitSomeDescs(@wndwObjSpec,@myAppleEvent,NIL,NIL,NIL);
  9736.   { currently we're not using defReply, so we won't init it }
  9737.   
  9738.   { make the window object }
  9739.   index := IndexFromWndwPtr(window);
  9740.   IF CheckErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,index,wndwObjSpec) , 6313 )
  9741.       THEN GOTO 9;    { finish up }
  9742.       
  9743.   { create event }
  9744.   IF CheckErr(   AECreateAppleEvent(kAECoreSuite,kAEClose,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,myAppleEvent) , 
  9745.       6314 ) THEN GOTO 9;    
  9746.       
  9747.   { add window object to event }
  9748.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyDirectObject,wndwObjSpec) , 6315 ) THEN GOTO 9;
  9749.   
  9750.   { add optional save param to event - we'll always include it }
  9751.   IF saveFlag THEN saveOpt := kAEYes ELSE saveOpt := kAENo;
  9752.   IF CheckErr(   AEPutParamPtr(myAppleEvent,keyAESaveOptions,typeEnumerated,@saveOpt,SizeOf(saveOpt)) ,
  9753.       6316 ) THEN GOTO 9;
  9754.       
  9755.   { see if we need to add the optional file param }
  9756.   IF fileParamFlag THEN
  9757.       IF CheckErr(   AEPutParamPtr(myAppleEvent,keyAEDestination,typeFSS,@fileSpec,SizeOf(fileSpec)) ,
  9758.           6317 ) THEN GOTO 9;
  9759.           
  9760.   { send the event }
  9761.   IF CheckErr(   AESend(myAppleEvent,defReply,kAENoReply+kAECanInteract,kAENormalPriority,kAEDefaultTimeOut,NIL,NIL) , 
  9762.       6318 ) THEN GOTO 9;
  9763.  
  9764. 9:    { finish up }
  9765.   gTempBool := CheckErr(   DisposeSomeDescs(@wndwObjSpec,@myAppleEvent,NIL,NIL,NIL) , 6319 );
  9766. END;    { SendAEClose }
  9767.  
  9768. {$S QuillNew}
  9769. PROCEDURE SendAEOpenDoc(myFSSpec: FSSpec);
  9770. { send the OpenDocs AppleEvent to myself, with a one-element list
  9771.   containing the given file spec
  9772.   INPUTS:    myFSSpec        file spec for file to be opened
  9773.   OUTPUTS:    none
  9774.   ERRORS:
  9775.   SIDE EFFECTS:
  9776.   NOTES:    the core AEOpenDocs event is defined as taking a list of
  9777.               aliases (not file specs) as its direct parameter.  However,
  9778.             we can send the file spec instead and depend on AppleEvents'
  9779.             automatic coercion.  In fact, we don't really even have to put 
  9780.             in a list; AppleEvents will coerce a descriptor into a 1-element
  9781.             list if called for.  In this routine, though, we'll make the
  9782.             list for demonstration purposes.
  9783. }
  9784. LABEL 9;
  9785. VAR myAppleEvent:    AppleEvent;
  9786.     defReply:        AppleEvent;
  9787.     docList:        AEDescList;
  9788. BEGIN
  9789.   InitSomeDescs(@myAppleEvent,@defReply,@docList,NIL,NIL);
  9790.   
  9791.   { step 1:  create empty list }
  9792.   IF CheckErr(   AECreateList(NIL,0,FALSE,docList) , 814 ) THEN EXIT(SendAEOpenDoc);
  9793.   
  9794.   { step 2:  add file spec to list }
  9795.   IF CheckErr(   AEPutPtr(docList,1,typeFSS,@myFSSpec,SizeOf(myFSSpec)) , 815 ) THEN GOTO 9;    { finish up } 
  9796.       
  9797.   { step 3:  create event }
  9798.   IF CheckErr(   AECreateAppleEvent(kCoreEventClass,kAEOpenDocuments,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,myAppleEvent) ,
  9799.       816 ) THEN GOTO 9;
  9800.     
  9801.   { step 4: add list to event }
  9802.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyDirectObject,docList) , 817 ) THEN GOTO 9;
  9803.  
  9804.   { step 5:  send event }
  9805.   gTempBool := CheckErr(   AESend(myAppleEvent,defReply,kAENoReply+kAEAlwaysInteract,kAENormalPriority,kAEDefaultTimeOut,NIL,NIL) ,
  9806.       818 );
  9807.       
  9808. 9:    { finish up }
  9809.   gTempBool := CheckErr(   DisposeSomeDescs(@myAppleEvent,@defReply,@docList,NIL,NIL) , 819 );
  9810. END;    { SendAEOpenDoc }
  9811.  
  9812. {$S QuillNew}
  9813. PROCEDURE SendAEPrintDoc(docDesc: AEDesc; doInteract: BOOLEAN);
  9814. { send the PrintDocs AppleEvent to myself, with a one-element list
  9815.   containing the given file spec
  9816.   INPUTS:    docDesc        descriptor for the document to be printed
  9817.               doInteract    TRUE if print routine should bring up the 
  9818.                         print dialog, FALSE o.w.
  9819.   OUTPUTS:    none
  9820.   ERRORS:
  9821.   SIDE EFFECTS:
  9822.   NOTES:    (1) The definition of the required AppleEvent PrintDocs 
  9823.                   calls for a list of aliases; our PrintDocs handler 
  9824.                 requests file specs or windows, which are the things
  9825.                 it knows how to print.  We can depend on coercion
  9826.                 handlers (built-in and/or ours) to coerce aliases
  9827.                 to files, objects to windows, etc., if possible.
  9828.                 In fact, we don't really even have to put the descriptor
  9829.                 in a list; AppleEvents will coerce a descriptor into a 
  9830.                 1-element list if called for.  In this routine, though, 
  9831.                 we'll make the list for demonstration purposes.
  9832.             (2) clearly this should be combined with SendAEOpenDoc; they're
  9833.                 almost exactly the same
  9834. }
  9835.  
  9836. LABEL 7,8;
  9837. VAR myAppleEvent:    AppleEvent;
  9838.     defReply:        AppleEvent;
  9839.     docList:        AEDescList;
  9840.     mySendMode:        AESendMode;
  9841. BEGIN
  9842.   { step 1:  create empty list }
  9843.   IF CheckErr(   AECreateList(NIL,0,FALSE,docList) , 1614 ) THEN EXIT(SendAEPrintDoc);
  9844.   
  9845.   { step 2:  add doc desc to list }
  9846.   IF CheckErr(   AEPutDesc(docList,1,docDesc) , 1615 ) THEN GOTO 8;    { dispose of list } 
  9847.       
  9848.   { step 3:  create event }
  9849.   IF CheckErr(   AECreateAppleEvent(kCoreEventClass,kAEPrintDocuments,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,myAppleEvent) ,
  9850.       1616 ) THEN GOTO 8;
  9851.     
  9852.   { step 4: add list to event }
  9853.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyDirectObject,docList) , 1617 ) THEN GOTO 7;    { dispose of event, list }
  9854.  
  9855.   { step 5:  send event }
  9856.   
  9857.   IF doInteract
  9858.   THEN mySendMode := kAENoReply+kAEAlwaysInteract
  9859.   ELSE mySendMode := kAENoReply+kAENeverInteract;
  9860.   
  9861.   IF CheckErr(   AESend(myAppleEvent,defReply,mySendMode,kAENormalPriority,kAEDefaultTimeOut,NIL,NIL) ,
  9862.       1618 ) THEN GOTO 7;
  9863.       
  9864. 7:    { dispose event }
  9865.   gTempBool := CheckErr(   AEDisposeDesc(myAppleEvent) , 1619 );
  9866.   
  9867. 8:    { dispose list }
  9868.   gTempBool := CheckErr(   AEDisposeDesc(docList) , 1620 );
  9869. END;    { SendAEPrintDoc }
  9870.  
  9871. {$S QuillNew}
  9872. PROCEDURE SendAEQuit(saveOpt: DescType);
  9873. { send a QuitEvent to myself
  9874.   INPUTS:    saveOpt        value for optional save parameter (we'll always send it):
  9875.                           kAEYes (save dirty windows, don't ask user), kAENo (don't
  9876.                         save any dirty windows), or kAEAsk (ask user on each
  9877.                         dirty window)
  9878.   OUTPUTS:    none
  9879.   SIDE EFFECTS:
  9880.   NOTES:    
  9881. }
  9882. LABEL 9;
  9883. VAR myAppleEvent:    AppleEvent;
  9884.     defReply:        AppleEvent;
  9885. BEGIN
  9886.   { create event }
  9887.   IF CheckErr(    AECreateAppleEvent(kCoreEventClass,kAEQuitApplication,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,myAppleEvent) , 1114)
  9888.       THEN EXIT(SendAEQuit);
  9889.       
  9890.   { add parameter }
  9891.   IF CheckErr(   AEPutParamPtr(myAppleEvent,keyAESaveOptions,typeEnumerated,@saveOpt,SizeOf(saveOpt)) ,
  9892.       1117 ) THEN GOTO 9;
  9893.       
  9894.   { send event }
  9895.   gTempBool := CheckErr(    AESend(myAppleEvent,defReply,kAENoReply+kAEAlwaysInteract,kAENormalPriority,kAEDefaultTimeOut,NIL,NIL) , 1115 );
  9896.   
  9897. 9:    { dispose event }
  9898.   gTempBool := CheckErr(   AEDisposeDesc(myAppleEvent) , 1116 );
  9899. END;    { SendAEQuit }
  9900.  
  9901. {$S QuillNew }    
  9902. PROCEDURE SendAESave(window: WindowPtr; fileParamFlag: BOOLEAN; 
  9903.     fileSpec: FSSpec);
  9904. { send an AppleEvent Save Event to myself, optionally including
  9905.   a file spec.  We'll bundle up the window as an object by index.
  9906.   INPUTS:    window                ptr to window to be save
  9907.               fileParamFlag        TRUE if file parameter is being supplied;
  9908.                                 FALSE o.w.
  9909.             fileSpec            file to save to; ignored if fileParamSpec is FALSE
  9910.   OUTPUTS:    none
  9911.   ERRORS:
  9912.   SIDE EFFECTS:
  9913. }
  9914. LABEL 9;
  9915. VAR index:                INTEGER;
  9916.     wndwObjSpec:        AEDesc;
  9917.     myAppleEvent:        AppleEvent;
  9918.     defReply:            AppleEvent;
  9919. BEGIN
  9920.   InitSomeDescs(@wndwObjSpec,@myAppleEvent,NIL,NIL,NIL);    { not using defReply this time around }
  9921.   
  9922.   { make the window object }
  9923.   index := IndexFromWndwPtr(window);
  9924.   IF CheckErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,index,wndwObjSpec) , 6913 ) 
  9925.       THEN GOTO 9;    { finish up }
  9926.       
  9927.   { create event }
  9928.     IF CheckErr(   AECreateAppleEvent(kAECoreSuite,kAESave,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,myAppleEvent) , 
  9929.       6914 ) THEN GOTO 9;
  9930.       
  9931.   { add window object to event }
  9932.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyDirectObject,wndwObjSpec) , 6915 ) THEN GOTO 9;
  9933.   
  9934.   { add optional file param if we need to }
  9935.   IF fileParamFlag THEN
  9936.       IF CheckErr(   AEPutParamPtr(myAppleEvent,keyAEDestination,typeFSS,@fileSpec,SizeOf(fileSpec)) , 
  9937.           6916 ) THEN GOTO 9;
  9938.           
  9939.   { send the event }
  9940.   gTempBool := CheckErr(   AESend(myAppleEvent,defReply,kAENoReply+kAECanInteract,kAENormalPriority,kAEDefaultTimeOut,NIL,NIL) ,
  9941.       6917 );
  9942.       
  9943. 9:    { finish up }
  9944.   gTempBool := CheckErr(   DisposeSomeDescs(@wndwObjSpec,@myAppleEvent,NIL,NIL,NIL) , 6918 );
  9945. END;    { SendAESave }
  9946.  
  9947. {$S QuillNew }
  9948. PROCEDURE SendAESetObjProp(theObj: AEDesc; theProp: DescType; theData: AEDesc);
  9949. { send the AppleEvent to set a given property of a given object to some value.
  9950.   INPUTS:    theObj        the object specifier (a desc, typeObjectSpecifier)
  9951.             theProp        prop to be set
  9952.             theData        value to set it to (a desc)
  9953. OUTPUTS:    none
  9954. ERRORS:
  9955. SIDE EFFECTS:
  9956. }
  9957. LABEL 8;
  9958. VAR propObjSpec:    AEDesc;
  9959.     myAppleEvent:    AppleEvent;
  9960.     defReply:        AppleEvent;
  9961. BEGIN
  9962.   { create an object spec that represents the property of the given object }
  9963.   IF CheckErr(   MakePropObjSpec(theObj,theProp,propObjSpec) , 5114 )
  9964.       THEN EXIT(SendAESetObjProp);    { dispose of addrDesc }
  9965.       
  9966.   { create event }
  9967.   IF CheckErr(   AECreateAppleEvent(kAECoreSuite,kAESetData,gSelfAddrDesc,kAutoGenerateReturnID,kAnyTransactionID,myAppleEvent) , 
  9968.       5115 ) THEN GOTO 8; { dispose of propObjSpec }
  9969.       
  9970.   { add prop obj spec to the event }
  9971.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyDirectObject,propObjSpec) , 5116 ) THEN GOTO 8;
  9972.   
  9973.   { add prop data to the event }
  9974.   IF CheckErr(   AEPutParamDesc(myAppleEvent,keyAEData,theData) , 5117 ) THEN GOTO 8;
  9975.   
  9976.   { send event }
  9977.   gTempBool := CheckErr(   AESend(myAppleEvent,defReply,kAENoReply+kAEAlwaysInteract,kAENormalPriority,kAEDefaultTimeOut,NIL,NIL) , 5118 );
  9978.   
  9979.   { dispose of event }    { **CHECK - anything else - like defReply? }
  9980.   gTempLong := AEDisposeDesc(myAppleEvent);
  9981.   
  9982. 8:    { dispose of propObjSepc }
  9983.   gTempLong :=  AEDisposeDesc(propObjSpec);
  9984. END;    { SendAESetObjProp }
  9985.  
  9986. {$S QuillNew }
  9987. PROCEDURE SendAESetWndwPos(index: INTEGER; thePos: Point);
  9988. { send the AppleEvent to set the position of a given window
  9989.   to a given rectangle.  The window is specified by 
  9990.   index (front-to-back ordering).  Position, here, is
  9991.   the top left corner of the structure region.
  9992.   INPUTS:    index        window index
  9993.               thePos        point to set the position to
  9994.   OUTPUTS:    none
  9995.   ERRORS:
  9996.   SIDE EFFECTS:
  9997. }
  9998. LABEL 8;
  9999. VAR windowObjSpec:    AEDesc;
  10000.     posDesc:        AEDesc;
  10001. BEGIN
  10002.   { turn window into an object spec desc }
  10003.   IF CheckErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,index,windowObjSpec) , 5313 )
  10004.       THEN EXIT(SendAESetWndwPos);
  10005.       
  10006.   { turn thePos into a desc }
  10007.   IF CheckErr(   AECreateDesc(typeQDPoint,@thePos,SizeOf(thePos),posDesc) , 5314 )
  10008.       THEN GOTO 8;    { dispose of windowObjSpec }
  10009.       
  10010.   SendAESetObjProp(windowObjSpec,pPosition,posDesc);
  10011.   
  10012.   { dispose of rectDesc }
  10013.   gTempLong := AEDisposeDesc(posDesc);
  10014.   
  10015. 8:    { dispose of windowObjSpec }
  10016.   gTempLong := AEDisposeDesc(windowObjSpec);
  10017. END;    { SendAESetWndwPos }
  10018.  
  10019. {$S QuillNew }
  10020. PROCEDURE SendAESetWndwRect(index: INTEGER; theRect: Rect);
  10021. { send the AppleEvent to set the rect of a given window
  10022.   to a given rectangle.  The window is specified by 
  10023.   index (front-to-back ordering).  The rect of a window, 
  10024.   here, means the rect of its structure region.
  10025.   INPUTS:    index        window index
  10026.               theRect        rect to set it to
  10027.   OUTPUTS:    none
  10028.   ERRORS:
  10029.   SIDE EFFECTS:
  10030. }
  10031. LABEL 8;
  10032. VAR windowObjSpec:    AEDesc;
  10033.     rectDesc:        AEDesc;
  10034. BEGIN
  10035.   { turn window into an object spec desc }
  10036.   IF CheckErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,index,windowObjSpec) , 5013 )
  10037.       THEN EXIT(SendAESetWndwRect);
  10038.       
  10039.   { turn rect into a desc }
  10040.   IF CheckErr(   AECreateDesc(typeQDRectangle,@theRect,SizeOf(theRect),rectDesc) , 5014 )
  10041.       THEN GOTO 8;    { dispose of windowObjSpec }
  10042.       
  10043.   SendAESetObjProp(windowObjSpec,pBounds,rectDesc);
  10044.   
  10045.   { dispose of rectDesc }
  10046.   gTempLong := AEDisposeDesc(rectDesc);
  10047.   
  10048. 8:    { dispose of windowObjSpec }
  10049.   gTempLong := AEDisposeDesc(windowObjSpec);
  10050. END;    { SendAESetWndwRect }
  10051.  
  10052. {$S QuillNew}
  10053. FUNCTION SetDataForAppProp(appPropDesc: AEDesc; propDataDesc: AEDesc): OSErr;
  10054. { given a descriptor that represents a property of the app - which 
  10055.   should be of, or coerceible to, typeMyAppProp - and a descriptor
  10056.   containing data that the prop could resonably be set to, set the 
  10057.   app property to that data
  10058.   INPUTS:    appPropDesc            a descriptor representing the app property;
  10059.                                   must be of, or coercible to, typeMyAppProp
  10060.               propDataDesc        a descriptor containing data to set the property to
  10061.   OUTPUTS:    error code (noErr if none)
  10062.   NOTES:
  10063.       09/17/91    BHM        formerly SetPropForApp
  10064.     09/17/91    BHM        now uses GetSingularData (so propDataDesc can be an object)
  10065.     02/17/92    BHM        added pUserSelction
  10066. }
  10067. LABEL 9;
  10068. VAR myErr:        OSErr;
  10069.     myAppProp:    DescType;
  10070.     window:        WindowPtr;
  10071.     myToken:    TextToken;
  10072.     newDesc:    AEDesc;
  10073.     myErrMode:    DescType;
  10074. BEGIN
  10075.   myErr := genericErr;
  10076.   newDesc := gNullDesc;
  10077.   
  10078.   { which prop? }
  10079.   IF CatchErr(   MyAECoerceDescPtr(appPropDesc,typeMyAppProp,@myAppProp,
  10080.       SizeOf(myAppProp),gActSize) , 18313 , myErr ) THEN GOTO 9;
  10081.       
  10082.   IF myAppProp = pUserSelection THEN
  10083.     BEGIN
  10084.       { get the user selection as a text token, if possible }
  10085.       window := FrontWindow;
  10086.       IF window = NIL THEN
  10087.         BEGIN
  10088.           gTempBool := CatchErr(   errAENoUserSelection , 18314 , myErr );
  10089.           GOTO 9;
  10090.         END;
  10091.         
  10092.       { make the token }
  10093.       MakeSelTextToken(window,myToken);
  10094.       
  10095.       { make a descriptor out of it, just for convenience }
  10096.       { **CHECK - the convenience has to do with the arguments of the existing }
  10097.       { SetStylTextData - but that's not a GOOD reason for this wasted effort  }
  10098.       IF CatchErr(   AECreateDesc(typeMyText,@myToken,SizeOf(myToken),newDesc) , 18315 , myErr )
  10099.           THEN GOTO 9;
  10100.       
  10101.       { and set the data for it }
  10102.       gTempBool := CatchErr(   SetStylTextData(newDesc,propDataDesc) , 18316 , myErr );
  10103.       GOTO 9;
  10104.     END;    { pUserSelection }
  10105.     
  10106.   IF myAppProp = pErrMode THEN
  10107.     BEGIN
  10108.       { what data? }
  10109.       IF CatchErr(   GetSingularData(propDataDesc,typeEnumerated,newDesc) , 18317 , myErr )
  10110.           THEN GOTO 9;
  10111.       IF CatchErr(   MyAECoerceDescPtr(newDesc,typeEnumerated,@myErrMode,SizeOf(myErrMode),gActSize) ,
  10112.           18318 , myErr ) THEN GOTO 9;    { we COULD go directly into the handle here }
  10113.           
  10114.       myErr := noErr;    { assume for 2 lines }
  10115.       IF myErrMode = kShowAllErrs THEN gShowAllErrs := TRUE
  10116.       ELSE IF myErrMode = kShowFewErrs THEN gShowAllErrs := FALSE
  10117.       ELSE gTempBool := CatchErr(   errAEWrongDataType , 18319 , myErr );
  10118.       
  10119.       GOTO 9;
  10120.     END;    { pErrMode }
  10121.     
  10122.   { if we get to here, it's a prop we've never heard of }
  10123.   gTempBool := CatchErr(   errAEWrongDataType , 18320 , myErr );
  10124.   
  10125. 9:    { finish up }
  10126.  
  10127.   gTempBool := CheckErr(   AEDisposeDesc(newDesc) , 18321 );
  10128.   
  10129.   SetDataForAppProp := myErr;
  10130. END;    { SetDataForAppProp }
  10131.  
  10132.  
  10133. {$S QuillNew}
  10134. FUNCTION SetDataForTextProp(textPropDesc: AEDesc; propDataDesc: AEDesc): OSErr;
  10135. { given a descriptor that represents a property of a window - which
  10136.   should be of, or coercible to, typeMyTextProp - and a descriptor
  10137.   containing data that the prop could reasonably be set to, set the
  10138.   text property to that data.
  10139.   INPUTS:    textPropDesc        a descriptor representing the property
  10140.                                   of some text.  Must be of, or coercible
  10141.                                 to, typeMyTextProp.
  10142.             propDataDesc        a descriptor containing data to set the property to
  10143.   OUTPUTS:    error code (noErr if none)
  10144.   NOTES:    we may want to break this one up differently later (in particular,
  10145.               the style stuff has gotten more complicated, and should be broken out)
  10146.             08/01/91    BHM        For styles, threw in a coercion to typeAEList, so that
  10147.                                 we can accept a single style item (not in a list)
  10148.                                 (the coercion routine itself is built in to AE Mngr)
  10149.             09/17/91    BHM        Formerly SetPropForText
  10150.             09/17/91    BHM        Now uses GetSingularData, so propDataDesc can be an object
  10151.                                 (but have we, in some cases, lost one level of coercion - **CHECK)
  10152. }
  10153. LABEL 9;
  10154. VAR myErr:                OSErr;
  10155.     myTextProp:            TextPropToken;
  10156.     myProp:                DescType;
  10157.     newDesc:            AEDesc;
  10158.     newSize:            INTEGER;
  10159.     newStyle:            TextStyle;
  10160.     mode:                INTEGER;
  10161.     nameDesc:            AEDesc;
  10162.     nameStr:            Str255;
  10163.     actSize:            LongInt;
  10164.     fontNum:            INTEGER;
  10165.     wndwTE:                TEHandle;
  10166.     onStyles:            Style;
  10167.     offStyles:            Style;
  10168.     onStylesNotNull:    BOOLEAN;
  10169.     styleDesc:            AEDescList;
  10170. BEGIN
  10171.   myErr := genericErr;
  10172.   InitSomeDescs(@nameDesc,@styleDesc,@newDesc,NIL,NIL);
  10173.   
  10174.   IF CatchErr(   MyAECoerceDescPtr(textPropDesc,typeMyTextProp,@myTextProp,SizeOf(myTextProp),
  10175.       gActSize) , 16413 , myErr ) THEN GOTO 9;
  10176.       
  10177.   myProp := myTextProp.tpProp;
  10178.   
  10179.   IF myProp = pPointSize THEN
  10180.     BEGIN
  10181.       IF CatchErr(   GetSingularData(propDataDesc,typeShortInteger,newDesc) , 16421 , myErr ) 
  10182.           THEN GOTO 9;
  10183.       IF CatchErr(   MyAECoerceDescPtr(propDataDesc,typeShortInteger,@newSize,SizeOf(newSize),
  10184.           gActSize) , 16414 , myErr ) THEN GOTO 9;
  10185.       { we could skip the above step and go directly into the handle for the next }
  10186.       newStyle.tsSize := newSize;
  10187.       mode := doSize;
  10188.     END    { set-up for pPointSize }
  10189.     
  10190.   ELSE IF myProp = pFont THEN
  10191.     BEGIN
  10192.       IF CatchErr(   GetSingularData(propDataDesc,typeChar,nameDesc) , 16419 , myErr ) THEN GOTO 9;
  10193.       IF CatchErr(   TextDescToStr(nameDesc,nameStr,actSize) , 16420 , myErr ) THEN GOTO 9;
  10194.       
  10195.       IF actSize > 255 THEN
  10196.         BEGIN
  10197.           { font name illegally long }
  10198.           gTempBool := CatchErr(   errAEBadData , 16421 , myErr );
  10199.           GOTO 9;
  10200.         END;
  10201.         
  10202.       GetFNum(nameStr,fontNum);
  10203.           
  10204.       newStyle.tsFont := fontNum;
  10205.       mode := doFont;
  10206.     END    { set-up for pFont }
  10207.     
  10208.   ELSE IF myProp = pTextStyles THEN
  10209.     BEGIN
  10210.       IF CatchErr(   GetSingularData(propDataDesc,typeTextStyles,styleDesc) , 16417 , myErr ) THEN GOTO 9;
  10211.       IF CatchErr(   StyleDescToStyleSets(styleDesc,onStyles,offStyles,TRUE) , 16416 , myErr )
  10212.         THEN GOTO 9;
  10213.     END    { set-up for pTextStyles }
  10214.     
  10215.   ELSE 
  10216.     BEGIN
  10217.       { not a property we can handle }
  10218.       myErr := errAEWrongDataType;
  10219.       GOTO 9;
  10220.     END;
  10221.     
  10222.   { we have a prop to set }
  10223.   { first, select text }
  10224.   WITH myTextProp.tpText DO
  10225.     BEGIN
  10226.       wndwTE := DocumentPeek(tokenWndw)^.docTE;
  10227.       TESetSelect(tokenOffset,tokenOffset + tokenLength,wndwTE);
  10228.     END;
  10229.     
  10230.   { and set the new value }
  10231.   { for now, we have to special-case face, because we have "on" and "off" }
  10232.   
  10233.   IF myProp = pTextStyles THEN
  10234.     BEGIN
  10235.       { **CHECK - on doToggle with plain, and note #131 }
  10236. { to turn off the offStyles, without affecting the others,
  10237.   we use the following scheme:
  10238.   (1) turn them all ON
  10239.   (2) use doToggle to turn them OFF
  10240.   doToggle doesn't work right with Plain, and anyway in the
  10241.   offStyles = Plain case we don't really have to do anything
  10242.   with the offStyles, so we'll skip it
  10243. }
  10244.       onStylesNotNull := (onStyles <> []);    { handy later }
  10245.       
  10246.       IF offStyles <> [] THEN
  10247.         BEGIN
  10248.           { offStyles not empty }
  10249.           { so, first, "turn the offs ON" }
  10250.           newStyle.tsFace := offStyles;
  10251.           TESetStyle(doFace,newStyle,FALSE,wndwTE);    { don't redraw }
  10252.           { now turn them off, using doToggle }
  10253.           TESetStyle(doFace + doToggle,newStyle,(NOT onStylesNotNull),wndwTE);    { redraw only if onStyles null, i.e., no more style changes }
  10254.         END;    { of offStyles not empty }
  10255.  
  10256. { now turn ON the on's - EXCEPT: if onStyles is empty,
  10257.   we don't want to make the call to TESetStyle, because
  10258.   that would set the style to Plain (i.e., turn everything
  10259.   off)                                
  10260. }
  10261.       IF onStylesNotNull THEN
  10262.         BEGIN
  10263.           newStyle.tsFace := onStyles;
  10264.           TESetStyle(doFace,newStyle,TRUE,wndwTE);    { ok, redraw }
  10265.         END;
  10266.         
  10267.     END    { of pTextStyles }
  10268.     
  10269.   ELSE TESetStyle(mode,newStyle,TRUE,wndwTE);    { this is for props other than pTextStyles, so far }
  10270.   
  10271.   DirtyWindow(myTextProp.tpText.tokenWndw);
  10272.   myErr := noErr;
  10273.   
  10274. 9:    { finish up }
  10275.   gTempBool := CheckErr(   DisposeSomeDescs(@nameDesc,@styleDesc,@newDesc,NIL,NIL) , 16418 );
  10276.   
  10277.   SetDataForTextProp := myErr;
  10278. END;    { SetDataForTextProp }
  10279.  
  10280.  
  10281. {$S QuillNew2}
  10282. FUNCTION SetDataForToken(myToken: AEDesc; dataDesc: AEDesc): OSErr;
  10283. { given one of my private tokens, set it to the given data.  The data
  10284.   can either be raw (a data descriptor), or an object - however, for now 
  10285.   at least, it can't be an object that resolves to a list.
  10286.   
  10287.   This routine only takes tokens (for myToken), not objects or lists.
  10288.   
  10289.   INPUTS:    myToken        token representing the thing whose data is to be set
  10290.               dataDesc    descriptor containing the data (either raw or as an object)
  10291.   OUTPUTS:    error code (noErr if none)
  10292.   
  10293.   **CHECK - QUESTION - should we pry the tokens out of their descriptors here, or leave
  10294.   that for further down? (for now, we'll push it further down)
  10295.   (also note IF-THEN-ELSE structure, which may be useful in similar routines.  What I
  10296.   really want is a CASE on types!)
  10297.   (ALSO note:  without the "paper-trail" CatchErr calls, this could all be in "SetDataForToken :=  . . ."
  10298.   form)
  10299. }
  10300. VAR myErr:    OSErr;
  10301.     myType:    DescType;
  10302. BEGIN
  10303.   myErr := genericErr;
  10304.   
  10305.   myType := myToken.descriptorType;
  10306.   
  10307.   IF myType = typeMyWndwProp THEN
  10308.       gTempBool := CatchErr(   SetDataForWndwProp(myToken,dataDesc) , 20813 , myErr )    { like old SetPropForWndwDesc }
  10309.       
  10310.   ELSE IF myType = typeMyText THEN
  10311.       gTempBool := CatchErr(   SetStylTextData(myToken,dataDesc) , 20814 , myErr )
  10312.       
  10313.   ELSE IF myType = typeMyTextProp THEN
  10314.       gTempBool := CatchErr(   SetDataForTextProp(myToken,dataDesc) , 20815 , myErr )    { old SetPropForText }
  10315.       
  10316.   ELSE IF myType = typeMyAppProp THEN
  10317.       gTempBool := CatchErr(   SetDataForAppProp(myToken,dataDesc) , 20816 , myErr )    { old SetPropForApp }
  10318.       
  10319.   ELSE myErr := errAEWrongDataType;    { nothing we know how to set the data of }
  10320.   
  10321.   SetDataForToken := myErr;
  10322. END;    { SetDataForToken }
  10323.  
  10324. {$S QuillNew2}
  10325. FUNCTION SetDataForTokenList(myList: AEDesc; dataDesc: AEDesc): OSErr;
  10326. { this routine takes a "token list" and sets the data for each token in 
  10327.   it to a given value.  The elements of the token list may themselves be
  10328.   lists or tokens, but the ultimate "node elements" of the list have to be
  10329.   tokens.
  10330.   
  10331.   The data supplied may either be raw data or an object specifier that
  10332.   resolves to a single object; it may not resolve to a list.  For now.
  10333.   
  10334.   INPUTS:    myList        the "token list"
  10335.               dataDesc    data descriptor; may be raw data or an object (but the
  10336.                         object may not resolve to a list)
  10337.   OUTPUTS:    error code (noErr if none)
  10338.   NOTES:    (1) it would actually be very powerful to allow dataDesc to be a list
  10339.               (possibly with a special typeDataList, to distinguish it from data values
  10340.             that happen to be lists all by themselves) with the same list structure 
  10341.             as myList, and set values on a 1-by-1 basis.  Future direction.
  10342.             (2) right now dataDesc gets resolved (if it's an object) and/or
  10343.             coerced to the right data type once for each element in myList, because
  10344.             we don't know what type's needed until we get to the individual elements.
  10345.             For homogeneous lists - like the ones returned by the OSL - this seems
  10346.             like a lot of extra effort, and should be optimized.  Future direction.
  10347. }
  10348. LABEL 9;
  10349. VAR myErr:        OSErr;
  10350.     itemCount:    LongInt;
  10351.     i:            LongInt;
  10352.     thisItem:    AEDesc;
  10353. BEGIN
  10354.   myErr := genericErr;
  10355.   thisItem := gNullDesc;
  10356.   
  10357.   { count the items }
  10358.   IF CatchErr(   AECountItems(myList,itemCount) , 20913 , myErr ) THEN GOTO 9;
  10359.   
  10360.   IF itemCount = 0 THEN GOTO 9;
  10361.   
  10362.   { since we're setting data, go backwards through the list to avoid side effects }
  10363.   FOR i := itemCount DOWNTO 1 DO
  10364.     BEGIN
  10365.       { get the item }
  10366.       IF CatchErr(   AEGetNthDesc(myList,i,typeWildCard,gReturnedKeywd,thisItem) , 20914 , 
  10367.           myErr ) THEN GOTO 9;
  10368.           
  10369.       { if it's a list, call myself recursively }
  10370.       IF thisItem.descriptorType = typeAEList THEN
  10371.         BEGIN
  10372.           IF CatchErr(   SetDataForTokenList(thisItem,dataDesc) , 20915 , myErr )
  10373.               THEN GOTO 9;
  10374.         END
  10375.       ELSE
  10376.         BEGIN
  10377.           { otherwise assume it's a token }
  10378.           IF CatchErr(   SetDataForToken(thisItem,dataDesc) , 20916 , myErr )
  10379.               THEN GOTO 9;
  10380.         END;
  10381.         
  10382.       { dispose of this item }
  10383.       gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 20917 );
  10384.       thisItem := gNullDesc;    { just for neatness }
  10385.   END;    { of FOR loop }
  10386.   
  10387. 9:    { finish up }
  10388.  
  10389.   gTempBool := CheckErr(   AEDisposeDesc(thisItem) , 20918 );
  10390.   
  10391.   SetDataForTokenList := myErr;
  10392. END;    { SetDataForTokenList }
  10393.  
  10394. {$S QuillNew}
  10395. FUNCTION SetDataForWndwProp(wndwPropDesc: AEDesc; propDataDesc: AEDesc): OSErr;
  10396. { given a descriptor which represents a property of a window - and should
  10397.   be of, or coercible to, typeMyWndwProp - and a descriptor containing data
  10398.   that the prop could reasonably be set to - set the window property
  10399.   to that data.
  10400.   INPUTS:    wndwPropDesc    a descriptor representing a property of a window.
  10401.                               Must be of, or coercible to, typeMyWndwProp.
  10402.             propDataDesc    a descriptor containing data to set the property to
  10403.   OUTPUTS:    error code (noErr if none)
  10404.   NOTES:    this routine actually just grabs the window prop token out of its
  10405.               descriptor and calls SetWindowProp
  10406.             09/17/91    BHM        formerly SetPropForWndwDesc
  10407. }
  10408. LABEL 9;
  10409. VAR myErr:        OSErr;
  10410.     myWndwProp:    WndwPropToken;
  10411. BEGIN
  10412.   myErr := genericErr;    { or whatever }
  10413.   
  10414.   IF CatchErr(   MyAECoerceDescPtr(wndwPropDesc,typeMyWndwProp,@myWndwProp,
  10415.       SizeOf(myWndwProp),gActSize) , 15213 , myErr ) THEN GOTO 9;
  10416.     
  10417.   WITH myWndwProp DO
  10418.     BEGIN
  10419.       IF CatchErr(   SetWindowProp(wpWndw,wpProp,propDataDesc) , 15214 , 
  10420.           myErr ) THEN GOTO 9;
  10421.     END;
  10422.     
  10423. 9:    { finish up }
  10424.   SetDataForWndwProp := myErr;
  10425. END;    { SetDataForWndwProp }
  10426.  
  10427.  
  10428. {$S QuillNew}
  10429. PROCEDURE SetFontForSelText(window: WindowPtr; fontName: Str255);
  10430. { concoct an object for the selected text in the given window,
  10431.   and send a Set Data event to change the font of that text to
  10432.   the given font.
  10433.   INPUT:    window        ptr to the window
  10434.               fontName    name of the font
  10435.   OUTPUTS:    none
  10436.   NOTES:    the routine will complain (with CheckErr) if it
  10437.               encounters any errors, but it will not pass those
  10438.             errors on up to the calling function
  10439. }
  10440. LABEL 9;
  10441. VAR selText:    AEDesc;
  10442.     nameDesc:    AEDesc;
  10443. BEGIN
  10444.   InitSomeDescs(@selText,@nameDesc,NIL,NIL,NIL);
  10445.  
  10446.   { make an object representing the selected text }
  10447.   IF CheckErr(   SmartMakeSelTextObj(window,selText) , 16713 ) THEN GOTO 9;
  10448.   
  10449.   { make a text descriptor for the font name }
  10450.   IF CheckErr(   StrToTextDesc(fontName,nameDesc) , 16714 ) THEN GOTO 9;
  10451.   
  10452.   { now send the Set Data event to set this prop }
  10453.   SendAESetObjProp(selText,pFont,nameDesc);
  10454.   
  10455. 9:    { finish up }
  10456.   gTempBool := CheckErr(   DisposeSomeDescs(@selText,@nameDesc,NIL,NIL,NIL) , 16715 );
  10457. END;    { SetFontForSelText }
  10458.  
  10459.  
  10460.  
  10461.  
  10462. {$S QuillNew}
  10463. PROCEDURE SetSizeForSelText(window: WindowPtr; newSize: INTEGER);
  10464. { concoct an object for the selected text in the given window,
  10465.   and send a Set Data event to change the size of that text to
  10466.   the given size.
  10467.   INPUT:    window        ptr to the window
  10468.               newSize        new size for the text
  10469.   OUTPUTS:    none
  10470.   NOTES:    the routine will complain (with CheckErr) if it
  10471.               encounters any errors, but it will not pass those
  10472.             errors on up to the calling function
  10473. }
  10474. LABEL 9;
  10475. VAR selText:    AEDesc;
  10476.     sizeDesc:    AEDesc;
  10477. BEGIN
  10478.   InitSomeDescs(@selText,@sizeDesc,NIL,NIL,NIL);
  10479.  
  10480.   { make an object representing the selected text }
  10481.   IF CheckErr(   SmartMakeSelTextObj(window,selText) , 16813 ) THEN GOTO 9;
  10482.   
  10483.   { make a descriptor for the new size }
  10484.   IF CheckErr(   AECreateDesc(typeShortInteger,@newSize,SizeOf(newSize),sizeDesc) , 16814 ) THEN GOTO 9;
  10485.   
  10486.   { now send the Set Data event to set this prop }
  10487.   SendAESetObjProp(selText,pPointSize,sizeDesc);
  10488.   
  10489. 9:    { finish up }
  10490.   gTempBool := CheckErr(   DisposeSomeDescs(@selText,@sizeDesc,NIL,NIL,NIL) , 16815 );
  10491. END;    { SetSizeForSelText }
  10492.  
  10493.  
  10494. {$S QuillNew}
  10495. FUNCTION SetStyleForSelText(window: WindowPtr; onStyles: Style;
  10496.     offStyles: Style): OSErr;
  10497. { concoct an object for the selected text in the given window, and send a
  10498.   Set Data event to change the style of that text to the given values.  
  10499.   We provide one set of style items to be turned uniformly ON in the text,
  10500.   and one set to be turned uniformly OFF.  Any style item not present in
  10501.   either set should be left alone.  If a style item is in both sets, that's
  10502.   an error (errAEBadData)
  10503.   INPUTS:    window        ptr to the window
  10504.               onStyles    set of style items to be turned ON
  10505.             offStyles    set of style items to be turned OFF
  10506.   OUTPUTS:    error code (noErr if none)
  10507.   NOTES:    the call to StyleSetToList will report the "style item
  10508.               in both sets" err, so we don't need to check for it
  10509.             explicitly here
  10510.             ( **CHECK - we might want to make this more similar to 
  10511.             SetSizeForSelText, SetFontForSelText, in terms of error-
  10512.             reporting behavior)
  10513. }
  10514. LABEL 9;
  10515. VAR myErr:        OSErr;
  10516.     selText:    AEDesc;
  10517.     styleData:    AEDesc;
  10518.     count:        LongInt;
  10519. BEGIN
  10520.   myErr := genericErr;
  10521.   InitSomeDescs(@selText,@styleData,NIL,NIL,NIL);
  10522.   
  10523.   { make an object for the selected text }
  10524.   IF CatchErr(   SmartMakeSelTextObj(window,selText) , 16913 , myErr ) THEN GOTO 9;
  10525.   
  10526.   { make a typeTextStyles desc out of the styles }
  10527.   
  10528.   { **CHECK - should we special-case 1-item deals to record better? }
  10529.   { or more generally, if offStyles = [] . . . . }
  10530.   
  10531.   IF CatchErr(   SmartMakeStyleData(onStyles,offStyles,styleData) , 16914 , myErr )
  10532.       THEN GOTO 9;
  10533.   
  10534.   { send the Set Data event }
  10535.   SendAESetObjProp(selText,pTextStyles,styleData);
  10536.   
  10537. 9:    { finish up }
  10538.   gTempBool := CheckErr(   DisposeSomeDescs(@selText,@styleData,NIL,NIL,NIL) , 16915 );
  10539.   
  10540.   SetStyleForSelText := myErr;
  10541. END;    { SetStyleForSelText }
  10542.  
  10543. {$S QuillNew}
  10544. FUNCTION SetStylTextData(textDesc: AEDesc; dataDesc: AEDesc): OSErr;
  10545. { given a text descriptor (which must be of, or coercible to, typeMyText)
  10546.   and some text data (which must be of, or coercible to, either typeChar
  10547.   or typeStyledText), set that text to that text data
  10548.   INPUTS:    textDesc        descriptor for the text object.  Must be
  10549.                               of, or coercible to, typeMyText
  10550.             dataDesc        descriptor for the data to set the text 
  10551.                             object to.  Must be of, or coercible to,
  10552.                             either typeChar or typeStyledText
  10553.   OUTPUTS:    error code (noErr if none)
  10554.   NOTES:    right now we have a CoerceStylTextToText, but no 
  10555.               CoerceTextToStylText.  For this reason we check for 
  10556.             typeStyledText first.  I handle the two cases separately.
  10557.             In the future it may be better to coerce text to
  10558.             stylText, and have no special cases here, but I'm
  10559.             not comfortable with that yet.
  10560.             ALSO:  we may want to break this up into the part
  10561.             that makes descriptors into values, and the part
  10562.             that actually handles the text.
  10563.             09/17/91    BHM        now uses GetSingularData (so dataDesc can be typeObjectSpecifier)
  10564. }
  10565. LABEL 9;
  10566. VAR myErr:        OSErr;
  10567.     stylHandle:    Handle;
  10568.     myText:        TextToken;
  10569.     newDesc:    AEDesc;
  10570.     textData:    AEDesc;
  10571.     stylData:    AEDesc;
  10572.     textHndl:    Handle;
  10573.     wndwTE:        TEHandle;
  10574. BEGIN
  10575.   myErr := genericErr;    { or whatever }
  10576.   stylHandle := NIL;
  10577.   InitSomeDescs(@newDesc,@textData,@stylData,NIL,NIL);
  10578.   
  10579.   IF CatchErr(   MyAECoerceDescPtr(textDesc,typeMyText,@myText,SizeOf(myText),gActSize) ,
  10580.       15313 , myErr ) THEN GOTO 9;
  10581.       
  10582.   { try to pick up data as typeStyledText } 
  10583.   IF QuietGetSingularData(dataDesc,typeStyledText,newDesc) = noErr THEN
  10584.     BEGIN
  10585.       { got typeStyledText - now make it an AERecord }
  10586.       IF CatchErr(   MyAEChangeDescType(newDesc,typeAERecord) , 15314 , myErr )
  10587.           THEN GOTO 9;    { **CHECK MyAEChangeDescType }
  10588.           
  10589.       { get the text out of it }
  10590.       IF CatchErr(   AEGetKeyDesc(newDesc,keyAEText,typeChar,textData) , 15315 , myErr )
  10591.           THEN GOTO 9;
  10592.           
  10593.       { get the style info out }
  10594.       IF CatchErr(   AEGetKeyDesc(newDesc,keyAEStyles,typeScrapStyles,stylData) , 
  10595.           15316 , myErr ) THEN GOTO 9;
  10596.           
  10597.       stylHandle := stylData.dataHandle;
  10598.       IF GetHandleSize(stylHandle) = 0 THEN stylHandle := NIL;    { seems safer somehow }
  10599.     END    { of getting info out of typeStyledText }
  10600.   ELSE
  10601.     BEGIN
  10602.       { didn't get typeStyledText; try typeChar }
  10603.       IF QuietGetSingularData(dataDesc,typeChar,textData) <> noErr THEN
  10604.          BEGIN
  10605.            { didn't get either }
  10606.            myErr := errAEWrongDataType;
  10607.            GOTO 9;
  10608.          END;    { of didn't get either }
  10609.     END;    { of try for typeChar }
  10610.  
  10611.   { if we get here we at least have text, and stylData is either good or NIL }
  10612.   textHndl := textData.dataHandle; { should I **CHECK for 0 chars? }
  10613.   
  10614.   HLock(textHndl);
  10615.   
  10616.   { select text represented by myText }
  10617.   WITH myText DO
  10618.     BEGIN
  10619.       wndwTE := DocumentPeek(tokenWndw)^.docTE;
  10620.       TESetSelect(tokenOffset,tokenOffset + tokenLength,wndwTE);
  10621.     END;
  10622.     
  10623.   { delete existing chars }
  10624.   TEDelete(wndwTE);
  10625.   
  10626.   { put in new chars, possibly with style info }
  10627.   TEStylInsert(textHndl^,GetHandleSize(textHndl),StScrpHandle(stylHandle),wndwTE);
  10628.   
  10629.   HUnlock(textHndl);
  10630.   
  10631.   { everything looks good }
  10632.   DirtyWindow(myText.tokenWndw);
  10633.   myErr := noErr;
  10634.   
  10635. 9:    { finish up }
  10636.  
  10637.   gTempBool := CheckErr(DisposeSomeDescs(@newDesc,@textData,@stylData,NIL,NIL) , 15317 );
  10638.  
  10639.   SetStylTextData := myErr;
  10640. END;    { SetStylTextData }
  10641.  
  10642. {$S QuillNew}
  10643. FUNCTION SetUpEdit(theAppleEvent: AppleEvent; VAR window: WindowPtr): OSErr;
  10644. { this is the common code for the Cut, Copy, Paste, and Clear
  10645.   events.  It gets the direct object out of the Apple Event as
  10646.   a text token, selects the specified text, and returns a ptr to 
  10647.   the window the text is in.  If there is no direct object, we 
  10648.   default to the current selection; SetUpEdit returns a ptr to
  10649.   the front window (if there isn't any, that's an error).  If
  10650.   there is a direct object, but we can't get a text token from it,
  10651.   that's an error too.
  10652.   INPUTS:    theAppleEvent        the apple event
  10653.               window                return VAR for the window the text is in
  10654.   OUTPUTS:    error code (noErr if none)
  10655.   NOTES:
  10656.       02/20/92    BHM        Changed to resolve dir obj here (and to reject lists)
  10657. }
  10658. LABEL 9;
  10659. VAR myErr:            OSErr;
  10660.     paramErr:        OSErr;
  10661.     myDirObj:        AEDesc;
  10662.     resDesc:        AEDesc;
  10663.     myTextToken:    TextToken;
  10664. BEGIN
  10665.   myErr := genericErr;
  10666.   InitSomeDescs(@myDirObj,@resDesc,NIL,NIL,NIL);
  10667.   
  10668.   { get the direct object, if any }
  10669.   paramErr := AEGetParamDesc(theAppleEvent,keyDirectObject,typeObjectSpecifier,myDirObj);
  10670.   
  10671.   { ordinarily this event has no required parameters, but  }
  10672.   { it's best to check anyway (the client could add some ) }
  10673.   IF CatchErr(   GotRequiredParams(theAppleEvent) , 17613 , myErr ) THEN GOTO 9;
  10674.   
  10675.   { now let's work on the direct object, if any }
  10676.   IF paramErr = errAEDescNotFound THEN
  10677.     BEGIN
  10678.       { no direct object; return current window }
  10679.       window := FrontWindow;
  10680.       IF window = NIL THEN gTempBool := CatchErr(   errAENoSuchObject , 17614 , myErr )
  10681.       ELSE myErr := noErr;
  10682.       GOTO 9;
  10683.     END;
  10684.     
  10685.   IF paramErr = noErr THEN
  10686.     BEGIN
  10687.       { got a direct object; resolve it }
  10688.       IF CatchErr(   AEResolve(myDirObj,kAEIDoMinimum,resDesc) , 17615 , myErr ) THEN GOTO 9;
  10689.       
  10690.       { if it's a list, that's an error for me }
  10691.       IF resDesc.descriptorType = typeAEList THEN
  10692.         BEGIN
  10693.           gTempBool := CatchErr(   errAENotASingleObject , 17616 , myErr );
  10694.           GOTO 9;
  10695.         END;
  10696.         
  10697.       { it's an object; better be a text token }
  10698.       IF CatchErr(   MyAECoerceDescPtr(resDesc,typeMyText,@myTextToken,SizeOf(myTextToken),gActSize) , 17617 , 
  10699.           myErr ) THEN GOTO 9;
  10700.         
  10701.       { got a text token }
  10702.       window := myTextToken.tokenWndw;
  10703.       SelectTextToken(myTextToken);
  10704.       myErr := noErr;
  10705.       GOTO 9;
  10706.     END;
  10707.     
  10708.   { if we get here, we had some other trouble with the direct parameter }
  10709.   gTempBool := CatchErr(   paramErr , 17618 , myErr);
  10710.   
  10711. 9:    { finish up }
  10712.   gTempBool := CheckErr(   DisposeSomeDescs(@myDirObj,@resDesc,NIL,NIL,NIL) , 17619 );
  10713.  
  10714.   SetUpEdit := myErr;
  10715. END;    { SetUpEdit }
  10716.  
  10717.  
  10718. {$S QuillNew }
  10719. FUNCTION SetWindowProp(window: WindowPtr; theProp: DescType; 
  10720.     propData: AEDesc): OSErr;
  10721. { set a property of a window to some value
  10722.   INPUTS:    window                ptr to the window
  10723.             theProp                property to be set
  10724.             propData            value to set it to
  10725.   OUTPUTS:    error code (noErr if none)
  10726.   ERRORS:
  10727.   SIDE EFFECTS:
  10728.   NOTES:    I would rather do this as a CASE, but there are compiler problems
  10729.               09/17/91    BHM        (1) now uses GetSingularData (so propData can be an object)
  10730.                                 (2) this should be rewritten and cleaned up! (**CHECK)
  10731.             02/17/91    BHM        dropped pText, which is now pContents.  IMPORTANT:  pContents
  10732.                                 does not appear in this routine because the accessor turns it
  10733.                                 into a text token, which is handled over in SetStylTextData.
  10734.                                 This is EXPERIMENTAL - **CHECK
  10735. }
  10736. LABEL 9;
  10737. VAR myErr:        OSErr;
  10738.     newDesc:    AEDesc;
  10739.     myRect:        Rect;
  10740.     actSize:    Size;
  10741.     myPoint:    Point;
  10742.     oldName:    Str255;
  10743.     newName:    Str255;
  10744.     myText:        TextToken;
  10745. BEGIN
  10746.   myErr := genericErr;
  10747.   newDesc := gNullDesc;
  10748.   
  10749.   IF theProp = pBounds THEN
  10750.     BEGIN
  10751.         
  10752.       { get the rectangle }
  10753.       IF CatchErr(   GetSingularData(propData,typeQDRectangle,newDesc) , 4013 , myErr ) THEN GOTO 9;
  10754.       IF CatchErr(   MyAECoerceDescPtr(newDesc,typeQDRectangle,@myRect,SizeOf(myRect),actSize) , 4014 , myErr )
  10755.         THEN GOTO 9;    { COULD just go into handle }
  10756.           
  10757.       { now set the property }
  10758.       WITH myRect DO
  10759.         BEGIN
  10760.           { the rectangle is for the structure region, and is in global coordinates }
  10761.           { MoveWindow and SizeWindow apply to the content region, so we have to massage a little }
  10762.           { the massage is specific to the type of window we are using }
  10763.           top := top+19;
  10764.           left := left+1;
  10765.           bottom := bottom-2;
  10766.           right := right-2;    {  should we **CHECK for bad values ? }
  10767.           
  10768.           { myRect is now adjusted for the content region }
  10769.           MoveWindow(window,left,top,FALSE);
  10770.           SizeWindow(window,right-left,bottom-top,TRUE);
  10771.         END;
  10772.         
  10773.         ResizeWindow(window);
  10774.         GOTO 9;
  10775.       END;    { IF pBounds }
  10776.       
  10777.   IF theProp = pPosition THEN
  10778.     BEGIN
  10779.  
  10780.       { get the point }
  10781.       IF CatchErr(   GetSingularData(propData,typeQDPoint,newDesc) , 4015 , myErr ) THEN GOTO 9;
  10782.       IF CatchErr(   MyAECoerceDescPtr(newDesc,typeQDPoint,@myPoint,SizeOf(myRect),actSize) , 4016 , myErr )
  10783.         THEN GOTO 9;
  10784.           
  10785.       { now set the property }
  10786.       WITH myPoint DO
  10787.         BEGIN
  10788.           { the point is for the structure region, and is in global coordinates }
  10789.           { MoveWindow applies to the content region, so we have to massage a little }
  10790.           { the massage is specific to the type of window we are using }
  10791.           v := v+19;
  10792.           h := h+1;
  10793.           
  10794.           { myPoint is now adjusted for the content region }
  10795.           MoveWindow(window,h,v,FALSE);
  10796.         END;
  10797.         
  10798.         ResizeWindow(window);
  10799.         GOTO 9;
  10800.       END;    { IF pPosition }      
  10801.       
  10802.   IF theProp = pName THEN
  10803.     BEGIN
  10804.         
  10805.       { get the name }
  10806.       IF CatchErr(   GetSingularData(propData,typeChar,newDesc) , 4017 , myErr ) THEN GOTO 9;
  10807.       IF CatchErr(   TextDescToStr(newDesc,newName,actSize) , 4018 , myErr ) THEN GOTO 9;
  10808.           
  10809.       { now set the property }
  10810.       GetWTitle(window,oldName);
  10811.       SetWTitle(window,newName);
  10812.       DirtyWindow(window);
  10813.       { if the name has really changed, mark the docFile as invalid }
  10814.       IF NOT EqualString(oldName,newName,FALSE,TRUE)    { ignore case but not diacriticals }
  10815.          THEN DocumentPeek(window)^.docFile.vRefNum := badVRefNum;
  10816.       
  10817.       GOTO 9;
  10818.     END;    { IF pName }
  10819.     
  10820.   { can't handle this property }
  10821.   gTempBool := CatchErr(   errAEWrongDataType , 4020 , myErr );
  10822.   
  10823. 9:  { finish up }
  10824.   gTempBool := CheckErr(   AEDisposeDesc(newDesc) , 4021 );   
  10825.  
  10826.  
  10827.   SetWindowProp := myErr;
  10828. END;    { SetWindowProp }
  10829.  
  10830.  
  10831. {$S QuillNew }
  10832. PROCEDURE ShutTheWindow(window: WindowPtr);
  10833. { this routine actually closes down the window and 
  10834.   throws away all associated storage.
  10835.   INPUTS:    window        ptr to window
  10836.   OUTPUTS:    none
  10837.   ERRORS:
  10838.   SIDE EFFECTS:    decrements gNumDocuments (number of documents open)
  10839. }
  10840. BEGIN
  10841.   WITH DocumentPeek(window)^ DO IF docTE <> NIL THEN TEDispose(docTE);
  10842.   CloseWindow(window);
  10843.   DisposPtr(Ptr(window));
  10844.   gNumDocuments := gNumDocuments - 1;
  10845. END;    { ShutTheWindow }
  10846.  
  10847. {$S QuillNew }
  10848. FUNCTION SmartCloseAll(saveOpt: DescType;  VAR userCancelled: BOOLEAN):  OSErr;
  10849. { this is a cover proc for CloseAllNoSave, CloseAllWithSave,
  10850.   and CloseAllAskUser.  saveOpt can be kAENo (no save), kAEYes
  10851.   (with save), or kAEAsk (ask user).  In the "ask user" case,
  10852.   the routine will call AEInteractWithUser when it has to interact
  10853.   (and not before!), and will also give the user a chance to cancel
  10854.   with each dialog (dialogs will only be put up in the "ask user" case,
  10855.   and even then only for dirty windows).
  10856.   INPUTS:    saveOpt            save/don't save/ask user
  10857.               userCancelled    TRUE if user cancelled, FALSE o.w. (this
  10858.                             is only meaningful in the "ask user" case,
  10859.                             and will be set to FALSE for the other two.
  10860.                             If the call fails, userCancelled is undefined,
  10861.                             but we'll set it to FALSE then also
  10862.   OUTPUTS:    error code (noErr if none).  Note that the "no save" case
  10863.               can't generate an error
  10864.   ERRORS:
  10865.   SIDE EFFECTS:
  10866. }
  10867. BEGIN
  10868.   userCancelled := FALSE;
  10869.   
  10870.   IF saveOpt = kAENo THEN
  10871.     BEGIN
  10872.       CloseAllNoSave;
  10873.       SmartCloseAll := noErr;
  10874.       EXIT(SmartCloseAll);
  10875.     END;
  10876.     
  10877.   IF saveOpt = kAEYes THEN
  10878.     BEGIN
  10879.       SmartCloseAll := CloseAllWithSave;
  10880.       EXIT(SmartCloseAll);
  10881.     END;
  10882.     
  10883.   IF saveOpt = kAEAsk THEN
  10884.     BEGIN
  10885.       SmartCloseAll := CloseAllAskUser(userCancelled);
  10886.       EXIT(SmartCloseAll);
  10887.     END;
  10888.     
  10889.   { bad saveOpt value }
  10890.   DoMyErr(genericErr,8613);
  10891.   
  10892. END;    { SmartCloseAll }
  10893.  
  10894. {$S QuillNew2}
  10895. FUNCTION SmartMakeSelTextObj(window: WindowPtr; VAR selTextObj: AEDesc): OSErr;
  10896. VAR myErr:        OSErr;
  10897.     myToken:    TextToken;
  10898. BEGIN
  10899.   myErr := genericErr;
  10900.   selTextObj := gNullDesc;
  10901.   
  10902.   
  10903.   WITH DocumentPeek(window)^.docTE^^ DO
  10904.     BEGIN
  10905.       myToken.tokenOffset := selStart;
  10906.       myToken.tokenLength := selEnd - selStart;
  10907.     END;
  10908.     
  10909.   myToken.tokenWndw := window;
  10910.   myToken.tokenClass := cText;
  10911.   
  10912.   gTempBool := CatchErr(   SmartTokenRep(myToken,selTextObj) , 21813 , myErr );
  10913.   
  10914.   
  10915.   SmartMakeSelTextObj := myErr;
  10916. END;    { SmartMakeSelTextObj }
  10917.  
  10918. {$S QuillNew2}
  10919. FUNCTION SmartMakeStyleData(onStyles: Style; offStyles: Style;
  10920.     VAR styleData: AEDesc): OSErr;
  10921. { like StyleSetsToStyleDesc, this routine takes a collection of "on"
  10922.   styles and "off" styles and creates an AEDesc that represents the
  10923.   specified text style.  However, it produces a desc that may be
  10924.   better for recording purposes.  In particular, if the specified
  10925.   style is (equivalent to) Plain, we get the single enumerated value
  10926.   kAEPlain; if it's a single "on" style item (e.g., just bold), we get
  10927.   the corresponding enumerated value (kAEBold); and if, in other cases,
  10928.   offStyles is empty, then we just get a list of the "on" styles.
  10929.   
  10930.   When offStyles is not empty, and we're not in the Plain case, we get
  10931.   the "standard" typeTextStyles descriptor.  
  10932.   
  10933.   The point here is to be able to record "set the style to bold" rather
  10934.   than "set the style to: typeTextStyles[on:[bold],off:[]]" (or whatever
  10935.   the syntax would be for the full typeTextStyles desc).
  10936.   INPUTS:    onStyles        the style items to be turned on
  10937.               offStyles        the style items to be turned off
  10938.             styleData        return VAR for style info desc - type will be
  10939.                             either typeEnumerated, or typeAEList, or typeTextStyles
  10940.   OUTPUTS:    error code (noErr if none)
  10941.   NOTES:    it's important to note that HandleSetData can handle all 3 types because
  10942.               we have coercions to get from typeEnumerated and typeAEList to typeTextStyles
  10943. }
  10944. LABEL 9;
  10945. VAR myErr:        OSErr;
  10946.     thisVal:    DescType;
  10947.     onList:        AEDesc;
  10948.     itemCount:    LongInt;
  10949. BEGIN
  10950.   myErr := genericErr;
  10951.   InitSomeDescs(@styleData,@onList,NIL,NIL,NIL);
  10952.   
  10953.   { start by checking for Plain }
  10954.   IF (offStyles = gAllStyles) & (onStyles = []) THEN
  10955.     BEGIN
  10956.       { Plain case }
  10957.       thisVal := kAEPlain;
  10958.       gTempBool :=  CatchErr(   AECreateDesc(typeEnumerated,@thisVal,SizeOf(thisVal),styleData) ,
  10959.           22713 , myErr );
  10960.       GOTO 9;
  10961.     END;
  10962.     
  10963.   { maybe it's not even a special case }
  10964.   IF offStyles <> [] THEN
  10965.     BEGIN
  10966.       gTempBool := CatchErr(   StyleSetsToStyleDesc(onStyles,offStyles,styleData,TRUE,TRUE) , 22714 , myErr);
  10967.       GOTO 9;
  10968.     END;
  10969.     
  10970.   { well, it IS a special case - make a list, then check for number of elements }
  10971.   { **CHECK - is there REALLY no way to ask Pascal how large a set is? }
  10972.   
  10973.   IF CatchErr(   StyleSetToList(onStyles,onList) , 22715 , myErr ) THEN GOTO 9;
  10974.   
  10975.   { now, count the list }
  10976.   IF CatchErr(  AECountItems(onList,itemCount) , 22716 , myErr ) THEN GOTO 9;
  10977.   
  10978.   { if there's exactly one element, then get it out }
  10979.   IF itemCount = 1 THEN
  10980.     BEGIN
  10981.       IF CatchErr(   AEGetNthDesc(onList,1,typeEnumerated,gReturnedKeywd,styleData) , 
  10982.           22717 , myErr ) THEN GOTO 9;
  10983.     END
  10984.   ELSE
  10985.     BEGIN
  10986.       { count <> 1; just duplicate list }
  10987.       IF CatchErr(  AEDuplicateDesc(onList,styleData) , 22718 , myErr ) THEN GOTO 9;
  10988.     END;
  10989.     
  10990. 9:
  10991.   IF myErr <> noErr THEN gTempBool := CheckErr(   AEDisposeDesc(styleData) , 22719 );
  10992.   
  10993.   gTempBool := CheckErr(   AEDisposeDesc(onList) , 22720 );
  10994.   
  10995.   SmartMakeStyleData := myErr;
  10996. END;    { SmartMakeStyleData }
  10997.  
  10998. {$S QuillNew2}
  10999. FUNCTION SmartTokenRep(myToken: TextToken; VAR smartDesc: AEDesc): OSErr;
  11000. { this routine takes a text token and checks to see if it can be represented
  11001.   as a line, item, word, or char - or a range thereof.  It checks in that
  11002.   order; note that we can always represent things as ranges of characters
  11003.   if we have to (well, except "spots").
  11004.   INPUTS:    myToken            token representing the text
  11005.               smartDesc        object descriptor containing a "smart"
  11006.                             representation of the text
  11007.   OUTPUTS:    error code (noErr if none)
  11008.   NOTES:    I am not AT ALL happy with this brute-force routine, but it seems 
  11009.               to work; I'll get back to it.
  11010.     02/13/92    BHM        Now checks on textHndl before unlocking it (ugly bug)
  11011.     02/14/92    BHM        Fixed bug concerning words at the very beginning or end
  11012.                         of a window (I was relying on possibly uninitalized pointers
  11013.                         to check first and last characters)
  11014. }
  11015. LABEL 9;
  11016. CONST     kNoChar    =    1;
  11017.         kCR        =    2;
  11018.         kComma    =    3;
  11019.         kSpace    =    4;
  11020.         kOther    =    5;
  11021.  
  11022. VAR myErr:        OSErr;
  11023.     index:        LongInt;
  11024.     wndwObj:    AEDesc;
  11025.     textHndl:    Handle;
  11026.     textLength:    LongInt;
  11027.     textPtr:    Ptr;
  11028.     leftKind:    INTEGER;
  11029.     leftPtr:    Ptr;
  11030.     leftChar:    SignedByte;
  11031.     rightPtr:    Ptr;
  11032.     rightChar:    SignedByte;
  11033.     rightKind:    INTEGER;
  11034.     textKind:    DescType;
  11035.     firstChar:    SignedByte;
  11036.     lastChar:    SignedByte;
  11037.     leftIndex:    LongInt;
  11038.     rightIndex:    LongInt;
  11039.     leftToken:    TextToken;
  11040.     leftCount:    LongInt;
  11041.     leftDesc:    AEDesc;
  11042.     rightDesc:    AEDesc;
  11043.     elemCount:    LongInt;
  11044. BEGIN
  11045.   myErr := genericErr;
  11046.   InitSomeDescs(@smartDesc,@wndwObj,@leftDesc,@rightDesc,NIL);
  11047.   textHndl := NIL;
  11048.   
  11049.   WITH myToken DO
  11050.     BEGIN
  11051.     
  11052.       
  11053.       { make an obj spec for the window }
  11054.       index := IndexFromWndwPtr(tokenWndw);
  11055.       IF index = 0 THEN 
  11056.         BEGIN
  11057.           { no such window }
  11058.           gTempBool := CatchErr(   errAEBadData , 21713 , myErr );
  11059.           GOTO 9;
  11060.         END;
  11061.         
  11062.       IF CatchErr(   MakeObjSpecFromIndex(cDocument,gNullDesc,index,wndwObj) , 21714 , myErr )
  11063.           THEN GOTO 9;
  11064.           
  11065.       IF tokenLength = 0 THEN
  11066.         BEGIN
  11067.           { this, my friends, is a spot }
  11068.           gTempBool := CatchErr(   MakeObjSpecFromIndex(cSpot,wndwObj,tokenOffset+1,smartDesc) ,
  11069.               21715 , myErr );
  11070.           GOTO 9;
  11071.         END;
  11072.         
  11073.       { not a spot }
  11074.           
  11075.       WITH DocumentPeek(tokenWndw)^.docTE^^ DO
  11076.         BEGIN
  11077.           textHndl := hText;
  11078.           textLength := teLength;
  11079.         END;
  11080.         
  11081.         
  11082.       HLock(textHndl);
  11083.       textPtr := textHndl^;    { ptr to first char IN THE WINDOW }
  11084.       
  11085.       { classify the char to the left of the token }
  11086.       IF tokenOffset = 0 THEN leftKind := kNoChar
  11087.       ELSE
  11088.         BEGIN
  11089.           leftPtr := Ptr(ORD(textPtr) + tokenOffset - 1);    { the character just BEFORE the token }
  11090.           leftChar := leftPtr^;
  11091.           IF leftChar = asciiCR THEN leftKind := kCR
  11092.           ELSE IF leftChar = asciiComma THEN leftKind := kComma
  11093.           ELSE IF leftChar = asciiSpace THEN leftKind := kSpace
  11094.           ELSE leftKind := kOther;
  11095.         END;
  11096.         
  11097.       { now the char to the right }
  11098.       IF tokenOffset + tokenLength = textLength THEN rightKind := kNoChar
  11099.       ELSE
  11100.         BEGIN
  11101.           rightPtr := Ptr(ORD(textPtr) + tokenOffset + tokenLength);    { the character just AFTER }
  11102.           rightChar := rightPtr^;
  11103.           IF rightChar = asciiCR THEN rightKind := kCR
  11104.           ELSE IF rightChar = asciiComma THEN rightKind := kComma
  11105.           ELSE IF rightChar = asciiSpace THEN rightKind := kSpace
  11106.           ELSE rightKind := kOther;
  11107.         END;
  11108.         
  11109.       { now classify by pairs }
  11110.       textKind := cChar;    { the default }
  11111.       
  11112.       CASE rightKind OF
  11113.       
  11114.         kNoChar:
  11115.           CASE leftKind OF
  11116.             kNoChar:    textKind := cChar;{textKind := kAll;}    { a special case }    { **CHECK HANDLING OF IT NOW!** }
  11117.             kCR:        textKind := cLine;
  11118.             kComma:        textKind := cItem;
  11119.             kSpace:        textKind := cWord;    { maybe }
  11120.           END;
  11121.           
  11122.         kCR:
  11123.           CASE leftKind OF
  11124.             kNoChar:    textKind := cLine;
  11125.             kCR:        textKind := cLine;
  11126.           END;
  11127.           
  11128.         kComma:
  11129.           CASE leftKind OF
  11130.             kNoChar:    textKind := cItem;
  11131.             kComma:        textKind := cItem;
  11132.           END;
  11133.           
  11134.         kSpace:
  11135.           CASE leftKind OF
  11136.             kNoChar:    textKind := cWord;    { maybe }
  11137.             kSpace:        textKind := cWord;    { maybe }
  11138.           END;
  11139.           
  11140.       END;    { of CASE rightKind }
  11141.       
  11142.       IF textKind = cWord THEN
  11143.         BEGIN
  11144.           { your first and last chars must be non-spaces and non-CRs }
  11145.           { in order for you to be a word or range thereof           }
  11146.           firstChar := Ptr(ORD(textPtr) + tokenOffset)^;
  11147.           lastChar := Ptr(ORD(textPtr) + tokenOffset + tokenLength - 1)^;
  11148.           IF (firstChar = asciiSpace) | (firstChar = asciiCR) | (lastChar = asciiSpace) | (lastChar = asciiCR)
  11149.               THEN textKind := cChar;
  11150.         END;
  11151.         
  11152.       { so now we know what you are, or are a range of - let's figure out your index/indices  }
  11153.       { **CHECK - NOTE - we could use "first" and/or "last" if we wanted to - like "word 7 to }
  11154.       { last word", or whatever (skip it for now)                                             }
  11155.       
  11156.       IF textKind = cChar THEN
  11157.         BEGIN
  11158.           { char or range of chars - easy }
  11159.           leftIndex := tokenOffset + 1;
  11160.           rightIndex := tokenOffset + tokenLength;
  11161.         END
  11162.         
  11163.       ELSE
  11164.         BEGIN
  11165.           { line, item, or word - not so easy }
  11166.           IF leftKind = kNoChar THEN leftIndex := 1
  11167.           ELSE
  11168.             BEGIN
  11169.               { there's chars to the left of you - let's make a token for THEM }
  11170.               leftToken.tokenClass := cText;
  11171.               leftToken.tokenWndw := tokenWndw;
  11172.               leftToken.tokenOffset := 0;
  11173.               leftToken.tokenLength := tokenOffset;    { funny, inn't? }
  11174.               
  11175.               { **CHECK - HACK? }
  11176.               IF (textKind = cItem) | (textKind = cLine) THEN
  11177.                 leftToken.tokenLength := leftToken.tokenLength - 1;
  11178.               { that should skip us over the preceding delimiter . . . }
  11179.               
  11180.               { now count }
  11181.               IF CatchErr(   CountTextElems(leftToken,textKind,leftCount) , 21716 , myErr ) THEN GOTO 9;
  11182.               { that won't work for textKind = kAll! }
  11183.               
  11184.               leftIndex := leftCount + 1;    { that's you! }
  11185.             END;
  11186.               
  11187.           IF CatchErr(   CountTextElems(myToken,textKind,elemCount) , 21717 , myErr ) THEN GOTO 9;
  11188.           rightIndex := leftIndex + elemCount - 1;    { that's the other side of you }
  11189.         END;    { of getting indices for line, item, or word }
  11190.         
  11191.       { we now have indices for line, item, word, or char }
  11192.       IF leftIndex = rightIndex THEN
  11193.         BEGIN
  11194.           gTempBool := CatchErr(   MakeObjSpecFromIndex(textKind,wndwObj,leftIndex,smartDesc) , 21718 , myErr );
  11195.           GOTO 9;
  11196.         END;
  11197.         
  11198.       IF CatchErr(   MakeObjSpecFromIndex(textKind,wndwObj,leftIndex,leftDesc) , 21719 , myErr )
  11199.           THEN GOTO 9;
  11200.       IF CatchErr(   MakeObjSpecFromIndex(textKind,wndwObj,rightIndex,rightDesc) , 21720 , myErr )
  11201.           THEN GOTO 9;
  11202.           
  11203.       gTempBool := CatchErr(   MakeObjSpecFromRange(cChar,wndwObj,leftDesc,rightDesc,smartDesc) , 21721 , myErr );
  11204.           
  11205.   END;    { WITH myToken }
  11206.   
  11207. 9:    { finish up }
  11208.   
  11209.   IF textHndl <> NIL THEN HUnlock(textHndl);
  11210.   gTempBool := CheckErr(   DisposeSomeDescs(@wndwObj,@leftDesc,@rightDesc,NIL,NIL) , 21722 );
  11211.  
  11212.   SmartTokenRep := myErr;
  11213. END;    { SmartTokenRep }
  11214.  
  11215.  
  11216. {$S QuillNew2}
  11217. PROCEDURE StartKeyBuffering(key: CHAR; window: WindowPtr);
  11218. { this routine is called for the first key-character event
  11219.   going into an empty buffer ("empty", here, not only means
  11220.   no characters in the buffer, it means nothing has been typed
  11221.   since the buffer was last emptied - you could get a "zero
  11222.   characters" situation with a combination of deletes and 
  11223.   ordinary characters, but that's different from the buffer 
  11224.   being truly empty).  It sets up various values in the key 
  11225.   buffer and handles the first typed char.  The Delete char
  11226.   requires some special handling.
  11227.   INPUTS:    key            the character that's been typed
  11228.               window        ptr to the window being typed into
  11229.   OUTPUTS:    none
  11230.   NOTES:    we may want to do some more sophisticated error-handling
  11231. }
  11232. BEGIN
  11233.   WITH keyBuffer DO
  11234.     BEGIN
  11235.     
  11236.       IF NOT bufEmpty THEN
  11237.         BEGIN
  11238.           { **CHECK - this is temporary }
  11239.           DoMyAlert('Trouble - StartKeyBuffering called with non-empty buffer!');
  11240.           EXIT(StartKeyBuffering);
  11241.         END;
  11242.         
  11243.       IF CheckErr(   SmartMakeSelTextObj(window,bufDesc) , 22013 ) THEN EXIT(StartKeyBuffering);
  11244.         
  11245.       bufWndw := window;
  11246.       WITH DocumentPeek(window)^.docTE^^ DO
  11247.         BEGIN
  11248.           bufSelStart := selStart;
  11249.           bufSelEnd := selEnd;
  11250.         END;
  11251.         
  11252.       IF key <> CHR(kDelChar) THEN
  11253.         BEGIN
  11254.           { ordinary key }
  11255.           bufChars^^[0] := key;
  11256.           bufCharCount := 1;    { offset to location for NEXT char }
  11257.           bufDelCount := 0;
  11258.           bufEmpty := FALSE;
  11259.           EXIT(StartKeyBuffering);
  11260.         END;
  11261.         
  11262.       { if we get to here, it's a Delete character }
  11263.       
  11264.       { SPECIAL RULE:  if the original selection is non-empty, then don't count        }
  11265.       { the Delete - in this case only the selection is deleted, but no chars          }
  11266.       { before it.  But if the selection is empty, we have to count the Delete         }
  11267.       { so we can erase the char preceding the empty selection (the insertion pt).     }
  11268.       { This rule only applies when a Delete is the first char typed into the buffer.  }
  11269.       
  11270.       IF bufSelStart = bufSelEnd THEN bufDelCount := 1 ELSE bufDelCount := 0;
  11271.       bufCharCount := 0;
  11272.       bufEmpty := FALSE;
  11273.     END;    { of WITH keyBuffer }
  11274. END;    { StartKeyBuffering }
  11275.  
  11276.  
  11277. {$S QuillNew }
  11278. FUNCTION StrToTextDesc(srcStr: Str255; VAR textDesc: AEDesc): OSErr;
  11279. { this routine takes a Pascal string and converts it into a
  11280.   descriptor of type text
  11281.   INPUTS:    srcStr        Pascal string to be converted
  11282.               textDesc    return VAR for descriptor
  11283.   OUTPUTS:    error code (noErr if none)
  11284.   ERRORS:
  11285.   SIDE EFFECTS:
  11286.   NOTES:    if the call returns noErr, then it returns in textDesc
  11287.               a valid descriptor that the caller is responsible for
  11288.             disposing.  If it returns an error, the textDesc is undefined
  11289.             and doesn't have to be disposed
  11290. }
  11291. LABEL 9;
  11292. VAR myErr:        OSErr;
  11293.     srcPtr:        Ptr;
  11294.     srcLen:        Size;
  11295. BEGIN
  11296.   myErr := genericErr;
  11297.   
  11298.   srcPtr := Ptr(ORD4(@srcStr)+1);
  11299.   srcLen := length(srcStr);
  11300.   
  11301.   IF CatchErr(   AECreateDesc(typeChar,srcPtr,srcLen,textDesc) , 9113 , myErr )
  11302.       THEN GOTO 9;    { set function result }
  11303.       
  11304.   { everything fine }
  11305.   myErr := noErr;
  11306.   
  11307. 9:    { set function result }
  11308.   StrToTextDesc := myErr;
  11309. END;    { StrToTextDesc }
  11310.  
  11311. {$S QuillNew2}
  11312. FUNCTION StyleDescToStyleSets(styleDesc: AEDesc; VAR onStyles: Style;
  11313.     VAR offStyles: Style; checkStyles: BOOLEAN):  OSErr;
  11314. { this routine takes an AE desc of typeTextStyles and returns
  11315.   two style sets (QuickDraw type Style) corresponding to the
  11316.   "on styles" field and "off styles" field of the descriptor.
  11317.   There is also some optional error-checking on the validity 
  11318.   of the desc.
  11319.   INPUT:    styleDesc        a descriptor of typeTextStyles
  11320.               onStyles        return VAR for the set of all styles in the "on list" field
  11321.             offStyles        return VAR for the set of all styles in the "off list" field
  11322.             checkStyles        if TRUE, abort if myStyles has invalid data; if FALSE, do not check
  11323.   OUTPUTS:    error code (noErr if none)
  11324.   NOTES:    (1) this only handles typeTextStyles, not single style items or lists of
  11325.               style items; those types should be translated/coerced into typeTextStyles
  11326.             before they get here
  11327.             (2) if checkStyles is TRUE, the following conditions are checked:
  11328.             (a) for both the "on" list and the "off" list in styleDesc, all of
  11329.             the items should be style item constants - kAEBold, kAEUnderline, etc.,
  11330.             including possibly kAEPlain.  (ListToStyleSet does this check.)
  11331.             (b) kAEPlain should not be in the "off" list.
  11332.             (c) No style item constant can be in both lists. 
  11333. }
  11334. LABEL 9;
  11335. VAR myErr:        OSErr;
  11336.     stylRec:    AEDesc;
  11337.     offList:    AEDesc;
  11338.     plainFlag:    BOOLEAN;
  11339.     onList:        AEDesc;
  11340. BEGIN
  11341.   myErr := genericErr;
  11342.   InitSomeDescs(@stylRec,@offList,@onList,NIL,NIL);
  11343.   
  11344.   { make it a record }
  11345.   IF CatchErr(   AECoerceDesc(styleDesc,typeAERecord,stylRec) , 22213 , myErr ) THEN GOTO 9;
  11346.   
  11347.   { get the "off list" out }
  11348.   IF CatchErr(   AEGetKeyDesc(stylRec,keyAEOffStyles,typeAEList,offList) , 22215 , myErr ) THEN
  11349.       GOTO 9;
  11350.       
  11351.   { turn it into a style set }
  11352.   IF CatchErr(   ListToStyleSet(offList,offStyles,plainFlag,checkStyles) , 22216 , myErr )
  11353.       THEN GOTO 9;
  11354.       
  11355.   { check for Plain - shouldn't appear in offList }
  11356.   IF checkStyles & plainFlag THEN
  11357.     BEGIN
  11358.       gTempBool := CatchErr(   errAEBadData , 22217 , myErr );
  11359.       GOTO 9;
  11360.     END;
  11361.     
  11362.   { now get the "on list" } 
  11363.   IF CatchErr(   AEGetKeyDesc(stylRec,keyAEOnStyles,typeAEList,onList) , 22218 , myErr ) THEN
  11364.       GOTO 9;
  11365.       
  11366.   { turn it into a style set }
  11367.   IF CatchErr(   ListToStyleSet(onList,onStyles,plainFlag,checkStyles) , 22219 , myErr )
  11368.       THEN GOTO 9;
  11369.       
  11370.   { special-case plain - in onList, it overrides everything else }
  11371.   IF plainFlag THEN
  11372.     BEGIN
  11373.       onStyles := [];
  11374.       offStyles := gAllStyles;
  11375.       GOTO 9;
  11376.     END;
  11377.     
  11378.   { check overlap }
  11379.   IF checkStyles & (onStyles*offStyles <> []) THEN gTempBool := CatchErr(   errAEBadData , 22220 , myErr );
  11380.  
  11381. 9:
  11382.   IF myErr <> noErr THEN
  11383.     BEGIN
  11384.       { just for neatness }
  11385.       onStyles := [];
  11386.       offStyles := [];
  11387.     END;
  11388.     
  11389.   gTempBool := CheckErr(   DisposeSomeDescs(@stylRec,@offList,@onList,NIL,NIL) , 22221 );
  11390.   
  11391.   StyleDescToStyleSets := myErr;
  11392. END;    { StyleDescToStyleSets } 
  11393.  
  11394. {$S QuillNew2}
  11395. FUNCTION StyleSetsToStyleDesc(onStyles: Style; offStyles: Style; VAR styleDesc: AEDesc;
  11396.     checkStyles: BOOLEAN; usePlain: BOOLEAN):  OSErr;
  11397. { this routine takes two sets of text styles (each set of QD type Style) - an
  11398.   "on" set and an "off" set - and creates a corresponding descriptor of
  11399.   typeTextStyles.  Easy enough.
  11400.   
  11401.   In the case of Plain - that is, the "on" styles are empty and the "off" styles
  11402.   are EVERYTHING - the "on" list in the returned desc will either be empty (if the
  11403.   usePlain parameter is FALSE) or will contain the single item kAEPlain (if the usePlain
  11404.   parameter is TRUE).  This is because I can't decide right now which one I want.  In
  11405.   either case the "off" list will contain all legitimate styles.
  11406.   
  11407.   There's some optional error checking:  if checkStyles is TRUE, then the routine
  11408.   will abort if there are any style items in both the "on" styles and the "off"
  11409.   styles.
  11410.   
  11411.   INPUTS:    onStyles        set of styles to go in the "on" list
  11412.               offStyles        set of styles to go in the "off" list
  11413.             stylesDesc        return VAR for desc of typeTextStyles
  11414.             checkStyles        if TRUE, return error if "on" and "off"
  11415.                             styles overlap; if FALSE, ignore that condition
  11416.             usePlain        boolean that controls format of styles desc in
  11417.                             Plain case (see above)
  11418.   OUTPUTS:    error code (noErr if none)
  11419. }
  11420. LABEL 9;
  11421. VAR myErr:        OSErr;
  11422.     styleRec:    AEDesc;
  11423.     onList:        AEDesc;
  11424.     offList:    AEDesc;
  11425.     thisItem:    DescType;
  11426. BEGIN
  11427.   myErr := genericErr;
  11428.   InitSomeDescs(@styleDesc,@styleRec,@onList,@offList,NIL);
  11429.   
  11430.   IF checkStyles & (onStyles*offStyles <> []) THEN
  11431.     BEGIN
  11432.       gTempBool := CatchErr(   errAEBadData , 22513 , myErr );
  11433.       GOTO 9;
  11434.     END;
  11435.     
  11436.   { create record for text styles desc }
  11437.   IF CatchErr(   AECreateList(NIL,0,TRUE,styleRec) , 22514 , myErr ) THEN GOTO 9;
  11438.   
  11439.   
  11440.   { create list for "off" }
  11441.   IF CatchErr(   StyleSetToList(offStyles,offList) , 22515 , myErr ) THEN GOTO 9;
  11442.   
  11443.   { create list for "on" }
  11444.   IF CatchErr(   StyleSetToList(onStyles,onList) , 22516 , myErr ) THEN GOTO 9;
  11445.   
  11446.   { see if we have to append kAEPlain to "on" list }
  11447.   IF usePlain & (onStyles = []) & (offStyles = gAllStyles) THEN
  11448.     BEGIN
  11449.       { yes, we do }
  11450.       thisItem := kAEPlain;
  11451.       IF CatchErr(   AEPutPtr(onList,0,typeEnumerated,@thisItem,SizeOf(thisItem)) , 22517 , 
  11452.           myErr ) THEN GOTO 9;
  11453.     END;
  11454.     
  11455.   { now add the lists to the record }
  11456.   IF CatchErr(   AEPutKeyDesc(styleRec,keyAEOnStyles,onList) , 22518 , myErr )
  11457.       THEN GOTO 9;
  11458.       
  11459.   IF CatchErr(   AEPutKeyDesc(styleRec,keyAEOffStyles,offList) , 22519 , myErr )
  11460.       THEN GOTO 9;
  11461.       
  11462.   { and coerce the record to typeTextStyles }
  11463.   gTempBool := CatchErr(   AECoerceDesc(styleRec,typeTextStyles,styleDesc) , 22520 , 
  11464.       myErr );
  11465.       
  11466. 9:
  11467.   { we never need to dispose of styleDesc, even in the error case, because }
  11468.   { its creation is the last possible error                                 }
  11469.   
  11470.   gTempBool := CheckErr(   DisposeSomeDescs(@styleRec,@onList,@offList,NIL,NIL) , 22521 );
  11471.   
  11472.   StyleSetsToStyleDesc := myErr;
  11473. END;    { StyleSetsToStyleDesc }
  11474.  
  11475.  
  11476. {$S QuillNew2}
  11477. FUNCTION StyleSetToList(styleSet: Style; VAR stylList: AEDesc): OSErr;
  11478. { this routine takes a set of text style items (QD type Style) and returns
  11479.   a corresponding list of style constants (kAEBold, kAEUnderline, etc.).
  11480.   If the style set is empty, an empty list is returned (if you want to append
  11481.   kAEPlain to it, do it elsewhere; that decision should depend two style sets - 
  11482.   the "on" and the "off" - not just one).
  11483.   INPUTS:    styleSet        the set of style items
  11484.               stylList    return VAR for list of style item constants
  11485.   OUTPUTS:    error code (noErr if none)
  11486. }
  11487. LABEL 9;
  11488. VAR myErr:        OSErr;
  11489.     i:            INTEGER;            
  11490.     thisItem:    DescType;
  11491. BEGIN
  11492.   myErr := genericErr;
  11493.   stylList := gNullDesc;
  11494.   
  11495.   { create the list }
  11496.   IF CatchErr(   AECreateList(NIL,0,FALSE,stylList) , 22413 , myErr ) THEN GOTO 9;
  11497.   
  11498.   { step through the style item constants }
  11499.   FOR i := 1 TO kNumOfStyles DO
  11500.     BEGIN
  11501.       IF theStyles[i].stylItem IN styleSet THEN
  11502.         BEGIN
  11503.           { it's in the set, add constant to the list }
  11504.           thisItem := theStyles[i].stylConst;
  11505.           IF CatchErr(   AEPutPtr(stylList,0,typeEnumerated,@thisItem,SizeOf(thisItem)) , 22415 , myErr )
  11506.               THEN GOTO 9;
  11507.         END;    { of style item in set }
  11508.         
  11509.     END;    { of loop }
  11510.     
  11511. 9:
  11512.   IF myErr <> noErr THEN
  11513.       gTempBool := CheckErr(   AEDisposeDesc(stylList) , 22416 );    { only throw it away in error case }
  11514.       
  11515.   StyleSetToList := myErr;
  11516. END;    { StyleSetToList }
  11517.  
  11518.  
  11519. {$S QuillNew }
  11520. FUNCTION TERecToFile(teHndl: TEHandle; fileSpec: FSSpec): OSErr;
  11521. { open the file and write the text and style info for the given
  11522.   new-style TERec into it.  The file is in the "handle-list" format
  11523.   (see WriteHandlesToFile and FillHandlesFromFile), specifically:
  11524.       
  11525.     number of data blocks = 6        (2 bytes)
  11526.     size of text block                (4 bytes)
  11527.     text block                        (variable)
  11528.     size of style record block        (4 bytes)
  11529.     style record block                (variable)
  11530.     size of style table block        (4 bytes)
  11531.     style table block                (variable)
  11532.     size of line-height table block    (4 bytes)
  11533.     line-height table block            (variable)
  11534.     size of null-style block        (4 bytes)
  11535.     null-style block                (variable)
  11536.     size of null-scrap block        (4 bytes)
  11537.     null-scrap block                (variable)
  11538.     
  11539.   INPUTS:    teHndl        handle to new-style TERec (rec includes handle to style rec)
  11540.               fileSpec    FSSpec for the file
  11541.   OUTPUTS:    TRUE if successful, FALSE o.w.
  11542.   ERRORS:
  11543.   SIDE EFFECTS:
  11544.   NOTES:    this new version returns an OSErr instead of TRUE/FALSE;
  11545.               will replace old in due time
  11546. }
  11547. LABEL 8,9;
  11548. VAR refNum:            INTEGER;
  11549.     teListCount:    INTEGER;
  11550.     teInfoList:        ARRAY[1..6] OF Handle;
  11551.     myErr:            OSErr;
  11552.     xferCount:        INTEGER;
  11553.     styleHndl:        TEStyleHandle;
  11554. BEGIN
  11555.   IF CatchErr(   FSpOpenDF(fileSpec,0,refNum) , 513 , myErr ) THEN GOTO 9;    { set function value }
  11556.  
  11557.   IF CatchErr(   SetFPos(refNum,fsFromStart,0) , 514 , myErr ) THEN GOTO 8;    { must close file }
  11558.   
  11559.   teListCount := 6;
  11560.   
  11561.   teInfoList[1] := teHndl^^.hText;
  11562.   styleHndl := GetStylHandle(teHndl);
  11563.  
  11564.   IF CatchErr(   MemError , 515 , myErr ) THEN GOTO 8;    { old-fashioned teRec; probably we should deal with it better }
  11565.     
  11566.   teInfoList[2] := Handle(styleHndl);
  11567.   WITH styleHndl^^ DO    { I'm just getting some fields out, so I shouldn't need to lock it }
  11568.     BEGIN
  11569.       teInfoList[3] := Handle(styleTab);
  11570.       teInfoList[4] := Handle(lhTab);
  11571.       teInfoList[5] := Handle(nullStyle);
  11572.       teInfoList[6] := Handle(nullStyle^^.nullScrap);
  11573.     END;
  11574.  
  11575.   gTempBool := CatchErr(    WriteHandlesToFile(teListCount,@teInfoList,refNum,xferCount) ,
  11576.       516 , myErr );
  11577.  
  11578. 8:    { close file }
  11579.   gTempBool := CatchErr(   FSClose(refNum), 517 , myErr );
  11580.  
  11581. 9:    { set function value }
  11582.   TERecToFile := myErr;
  11583. END;    { TERecToFile }
  11584.  
  11585. {$S QuillNew }
  11586. FUNCTION TextDescToStr(textDesc: AEDesc; VAR destStr: Str255; VAR actSize: Size): OSErr;
  11587. { this routine takes a descriptor that contains text information
  11588.   (basically, anything that can be coerced to typeChar) and copies
  11589.   the text into a Pascal string.  The text will be truncated to 255 
  11590.   characters, if necessary; the actual size of the original text will
  11591.   also be returned.
  11592.   INPUTS:    textDesc    the descriptor containing the text
  11593.               destStr        return VAR for the string
  11594.             actSize        return VAR for the actual text length
  11595.   OUTPUTS:    error code (noErr if none).  Truncation is not an error.
  11596.   ERRORS:
  11597.   SIDE EFFECTS:
  11598.   NOTES:    clearly this belongs in a coercion handler
  11599. }
  11600. LABEL 9;
  11601. VAR myErr:        OSErr;
  11602.     destStrPtr:    Ptr;
  11603.     xferSize:    Size;
  11604. BEGIN
  11605.   myErr := genericErr;
  11606.   actSize := 0;
  11607.   destStr := 'bad string';
  11608.   
  11609.   destStrPtr := Ptr(ORD4(@destStr)+1);
  11610.   IF CatchErr(   MyAECoerceDescPtr(textDesc,typeChar,destStrPtr,255,actSize) , 
  11611.       9013, myErr ) THEN GOTO 9;    { set function result }
  11612.       
  11613.   xferSize := actSize;
  11614.   IF xferSize > 255 THEN xferSize := 255;
  11615.   destStrPtr := @destStr;
  11616.   destStrPtr^ := xferSize;
  11617.   
  11618.   { everything looks fine }
  11619.   myErr := noErr;
  11620.   
  11621. 9:    { set function result }
  11622.   TextDescToStr := myErr;
  11623. END;    { TextDescToStr }
  11624.  
  11625. {$S QuillNew2}
  11626. FUNCTION TextElemFromTextAccessor(wantClass: DescType; container: AEDesc ;
  11627.     containerClass: DescType; form: DescType; selectionData: AEDesc; VAR value: AEDesc;
  11628.     theRefCon: LongInt): OSErr;
  11629. { NOTES:    this should be combined with "FromWndw" version, and split
  11630.             up differently . . . .
  11631.             7/1/91    BHM        Added "spots".  NOTE: should probably take out the 0-length
  11632.                             special case now
  11633. }
  11634. LABEL 9;
  11635. VAR myErr:                OSErr;
  11636.     srcText:            TextToken;
  11637.     actSize:            Size;
  11638.     elemCount:            LongInt;
  11639.     allFlag:            BOOLEAN;
  11640.     zeroFlag:            BOOLEAN;
  11641.     index:                LongInt;
  11642.     elemText:            TextToken;
  11643.     selectionRecord:    AERecord;
  11644.     startText:            TextToken;
  11645.     returnedType:        DescType;
  11646.     stopText:            TextToken;
  11647.     newOffset:            LongInt;
  11648.     newLength:            LongInt;
  11649.     lastStartOff:        LongInt;
  11650.     lastStopOff:        LongInt;
  11651.     newLastOff:            LongInt;
  11652.     rangeText:            TextToken;
  11653. BEGIN
  11654.   myErr := accessorErr;    { or whatever }
  11655.   InitSomeDescs(@value,@selectionRecord,NIL,NIL,NIL);
  11656.   
  11657.   { let's get the src text }
  11658.   IF CatchErr(   MyAECoerceDescPtr(container,typeMyText,@srcText,SizeOf(srcText),actSize) ,
  11659.       13713 , myErr ) THEN GOTO 9;
  11660.       
  11661.   { now, how is the element specified? }
  11662.   IF form = formAbsolutePosition THEN
  11663.     BEGIN
  11664.     
  11665.       { count the items }
  11666.       IF CatchErr(   CountTextElems(srcText,wantClass,elemCount) , 13715 , myErr ) THEN GOTO 9;
  11667.       
  11668.       { get the element index }
  11669.       IF CatchErr(   DecodeOrdinal(selectionData,elemCount,index,allFlag,zeroFlag) , 13716 , 
  11670.           myErr ) THEN GOTO 9;
  11671.           
  11672.       IF allFlag THEN
  11673.         BEGIN
  11674.           myErr := MakeElemList(wantClass,srcText,value);
  11675.           GOTO 9;
  11676.         END;
  11677.         
  11678.       { some particular element }
  11679.       { get the element as a text token }
  11680.       IF CatchErr(   GetTextElemFromText(srcText,wantClass,index,elemText) , 13717 , myErr ) 
  11681.           THEN GOTO 9;
  11682.           
  11683.       { return it in a descriptor }
  11684.       gTempBool := CatchErr(   AECreateDesc(typeMyText,@elemText,SizeOf(elemText),value) , 13725 , myErr );
  11685.       GOTO 9;
  11686.     END;    { of formAbsolutePosition }
  11687.     
  11688.   
  11689.   IF form = formRange THEN
  11690.     BEGIN
  11691.       { coerce the selection data into an AERecord }
  11692.       IF CatchErr(   AECoerceDesc(selectionData,typeAERecord,selectionRecord) , 13719 , myErr ) 
  11693.           THEN GOTO 9;
  11694.           
  11695.       { get the start object as a text token }
  11696.       IF CatchErr(   AEGetKeyPtr(selectionRecord,keyAERangeStart,typeMyText,returnedType,
  11697.           @startText,SizeOf(startText),actSize) , 13720 , myErr ) THEN GOTO 9;
  11698.           
  11699.       { now the stop object }
  11700.       IF CatchErr(   AEGetKeyPtr(selectionRecord,keyAERangeStop,typeMyText,returnedType,
  11701.           @stopText,SizeOf(stopText),actSize) , 13721 , myErr ) THEN GOTO 9;
  11702.           
  11703.       WITH startText DO
  11704.         BEGIN
  11705.           { the windows have to be the same }
  11706.           { **CHECK on role of actual containers here, which may only be part of window }
  11707.           IF (tokenWndw <> stopText.tokenWndw) | (tokenWndw <> srcText.tokenWndw) THEN
  11708.             BEGIN
  11709.               gTempBool := CatchErr(   errAECorruptData , 13722 , myErr );    { or whatever }
  11710.               GOTO 9;
  11711.             END;
  11712.           { the definition we're using for "range" right now  }
  11713.           { is "from the left-most character in either of the }
  11714.           { two boundary objects to the right-most etc."  We  }
  11715.           { may want to reconsider this later - **CHECK       }
  11716.           
  11717.           { **SPECIAL CASE for "0-length ranges" - if the second token's last }
  11718.           { char is just to the left of the first token's first char          }
  11719.           
  11720.           IF tokenOffset = stopText.tokenOffset + stopText.tokenLength THEN
  11721.             BEGIN
  11722.               newOffset := tokenOffset;
  11723.               newLength := 0;
  11724.             END
  11725.           ELSE
  11726.             BEGIN
  11727.               { get some values for the new text token }
  11728.               IF tokenOffset < stopText.tokenOffset THEN newOffset := tokenOffset
  11729.               ELSE newOffset := stopText.tokenOffset;
  11730.           
  11731.               { we'll need offsets to last chars in each }
  11732.               lastStartOff := tokenOffset + tokenLength - 1;
  11733.               lastStopOff := stopText.tokenOffset + stopText.tokenLength - 1;
  11734.           
  11735.               IF lastStopOff > lastStartOff THEN newLastOff := lastStopOff
  11736.               ELSE newLastOff := lastStartOff;
  11737.           
  11738.               newLength := newLastOff - newOffset + 1;
  11739.             END;
  11740.         END;    { of WITH startText }
  11741.         
  11742.       { now make the new text token }
  11743.       WITH rangeText DO
  11744.         BEGIN
  11745.           tokenClass := wantClass;    { **CHECK if the wantClass should affect the calculations above }
  11746.           tokenWndw := srcText.tokenWndw;
  11747.           tokenOffset := newOffset;
  11748.           tokenLength := newLength;
  11749.         END;
  11750.         
  11751.       { and return it in a descriptor }
  11752.       gTempBool := CatchErr(   AECreateDesc(typeMyText,@rangeText,SizeOf(rangeText),value) , 13723 , myErr );
  11753.       GOTO 9;
  11754.     END;    { of formRange }
  11755.   
  11756.   
  11757.   { unsupported naming form }
  11758.   gTempBool := CatchErr(   errAEWrongDataType , 13718 , myErr );
  11759.   
  11760. 9:    { finish up }
  11761.   gTempBool := CheckErr(   AEDisposeDesc(selectionRecord) , 13724 );
  11762.   
  11763.   TextElemFromTextAccessor := myErr;
  11764. END;    { TextElemFromTextAccessor }
  11765.  
  11766. {$S QuillNew2}
  11767. FUNCTION TextElemFromWndwAccessor(wantClass: DescType; container: AEDesc ;
  11768.     containerClass: DescType; form: DescType; selectionData: AEDesc; VAR value: AEDesc;
  11769.     theRefCon: LongInt): OSErr;
  11770. { NOTES:    variable use here needs to be optimized, and in fact the routine
  11771.             should probably be split up based on form
  11772.             7/1/91    BHM        Added "spots".  NOTE: should probably take out the 0-length
  11773.                             special case now
  11774. }
  11775. LABEL 9;
  11776. VAR myErr:                OSErr;
  11777.     window:                WindowPtr;
  11778.     actSize:            Size;
  11779.     index:                LongInt;
  11780.     wndwText:            TextToken;
  11781.     elemText:            TextToken;
  11782.     selectionRecord:    AERecord;
  11783.     startText:            TextToken;
  11784.     returnedType:        DescType;
  11785.     stopText:            TextToken;
  11786.     newOffset:            LongInt;
  11787.     newLength:            LongInt;
  11788.     lastStartOff:        LongInt;
  11789.     lastStopOff:        LongInt;
  11790.     newLastOff:            LongInt;
  11791.     rangeText:            TextToken;
  11792.     allFlag:            BOOLEAN;
  11793.     zeroFlag:            BOOLEAN;
  11794.     elemCount:            LongInt;
  11795. BEGIN
  11796.   myErr := accessorErr;    { or whatever }
  11797.   InitSomeDescs(@value,@selectionRecord,NIL,NIL,NIL);
  11798.   
  11799.   { let's get the actual window }
  11800.   IF CatchErr(   MyAECoerceDescPtr(container,typeMyWndw,@window,SizeOf(window),actSize) , 
  11801.       13613 , myErr ) THEN GOTO 9;
  11802.       
  11803.   { now, how is the element specified? }
  11804.   IF form = formAbsolutePosition THEN
  11805.     BEGIN
  11806.       { make a text token representing the window's text }
  11807.       MakeTextTokenForWndw(window,wndwText);
  11808.       
  11809.       { count the items }
  11810.       IF CatchErr(   CountTextElems(wndwText,wantClass,elemCount) , 13626 , myErr ) THEN GOTO 9;
  11811.       
  11812.       { get the element index }
  11813.       IF CatchErr(   DecodeOrdinal(selectionData,elemCount,index,allFlag,zeroFlag) , 13627 , 
  11814.           myErr ) THEN GOTO 9;
  11815.           
  11816.       IF allFlag THEN
  11817.         BEGIN
  11818.           myErr := MakeElemList(wantClass,wndwText,value);
  11819.           GOTO 9;
  11820.         END;
  11821.         
  11822.       { some particular element }
  11823.       { get the element as a text token }
  11824.       IF CatchErr(   GetTextElemFromText(wndwText,wantClass,index,elemText) , 13617 , myErr ) 
  11825.           THEN GOTO 9;
  11826.           
  11827.       { return it in a descriptor }
  11828.       gTempBool := CatchErr(   AECreateDesc(typeMyText,@elemText,SizeOf(elemText),value) , 13618 , myErr );
  11829.       GOTO 9;
  11830.     END;    { of formAbsolutePosition }
  11831.     
  11832.   IF form = formRange THEN
  11833.     BEGIN
  11834.       { coerce the selection data into an AERecord }
  11835.       IF CatchErr(   AECoerceDesc(selectionData,typeAERecord,selectionRecord) , 13620 , myErr ) 
  11836.           THEN GOTO 9;
  11837.           
  11838.       { get the start object as a text token }
  11839.       IF CatchErr(   AEGetKeyPtr(selectionRecord,keyAERangeStart,typeMyText,returnedType,
  11840.           @startText,SizeOf(startText),actSize) , 13621 , myErr ) THEN GOTO 9;
  11841.           
  11842.       { now the stop object }
  11843.       IF CatchErr(   AEGetKeyPtr(selectionRecord,keyAERangeStop,typeMyText,returnedType,
  11844.           @stopText,SizeOf(stopText),actSize) , 13622 , myErr ) THEN GOTO 9;
  11845.           
  11846.       WITH startText DO
  11847.         BEGIN
  11848.           { the windows have to be the same }
  11849.           { **CHECK on role of actual containers here, which may only be part of window }
  11850.           IF (tokenWndw <> stopText.tokenWndw) | (tokenWndw <> window) THEN
  11851.             BEGIN
  11852.               gTempBool := CatchErr(   errAECorruptData , 13623 , myErr );    { or whatever }
  11853.               GOTO 9;
  11854.             END;
  11855.           { the definition we're using for "range" right now  }
  11856.           { is "from the left-most character in either of the }
  11857.           { two boundary objects to the right-most etc."  We  }
  11858.           { may want to reconsider this later - **CHECK       }
  11859.           
  11860.           { **SPECIAL CASE for "0-length ranges" - if the second token's last }
  11861.           { char is just to the left of the first token's first char         }
  11862.           
  11863.           IF tokenOffset = stopText.tokenOffset + stopText.tokenLength THEN
  11864.             BEGIN
  11865.               newOffset := tokenOffset;
  11866.               newLength := 0;
  11867.             END
  11868.           ELSE
  11869.             BEGIN
  11870.               { get some values for the new text token }
  11871.               IF tokenOffset < stopText.tokenOffset THEN newOffset := tokenOffset
  11872.               ELSE newOffset := stopText.tokenOffset;
  11873.           
  11874.               { we'll need offsets to last chars in each }
  11875.               lastStartOff := tokenOffset + tokenLength - 1;
  11876.               lastStopOff := stopText.tokenOffset + stopText.tokenLength - 1;
  11877.           
  11878.               IF lastStopOff > lastStartOff THEN newLastOff := lastStopOff
  11879.               ELSE newLastOff := lastStartOff;
  11880.           
  11881.               newLength := newLastOff - newOffset + 1;
  11882.             END;
  11883.         END;    { of WITH startText }
  11884.         
  11885.       { now make the new text token }
  11886.       WITH rangeText DO
  11887.         BEGIN
  11888.           tokenClass := wantClass;    { **CHECK if the wantClass should affect the calculations above }
  11889.           tokenWndw := window;
  11890.           tokenOffset := newOffset;
  11891.           tokenLength := newLength;
  11892.         END;
  11893.         
  11894.       { and return it in a descriptor }
  11895.       gTempBool := CatchErr(   AECreateDesc(typeMyText,@rangeText,SizeOf(rangeText),value) , 13624 , myErr );
  11896.       GOTO 9;
  11897.     END;    { of formRange }
  11898.     
  11899.   { unsupported naming form }
  11900.   gTempBool := CatchErr(   errAEWrongDataType , 13619 , myErr );
  11901.   
  11902. 9:    { finish up }
  11903.   gTempBool := CheckErr(   AEDisposeDesc(selectionRecord) , 13625 );
  11904.  
  11905.   TextElemFromWndwAccessor := myErr;
  11906. END;    { TextElemFromWndwAccessor }
  11907.  
  11908. {$S QuillNew2}
  11909. FUNCTION TextToIntlText(textDesc: AEDesc; scrptCode: ScriptCode; lngCode: LangCode;
  11910.     VAR intlTextDesc: AEDesc): OSErr;
  11911. { boring subroutine.  Given a text desc, along with a script code and language code,
  11912.   return a corresponding intl text desc (of typeIntlText)
  11913.   INPUTS:    textDesc        the text
  11914.               scrptCode        the script code
  11915.             lngCode            the language code
  11916.             intlTextDesc    return VAR for the intl text desc
  11917.   OUTPUTS:    error code (noErr if none)
  11918.   NOTES:    **CHECK - could I just make my own AEDesc, starting with a NewHandle,
  11919.               or do I have to let the AEM do it (which I do here, but it looks like
  11920.             unnecessary duplicating)?
  11921. }
  11922. LABEL 9;
  11923. VAR myErr:        OSErr;
  11924.     myHndl:        Handle;
  11925.     textLen:    LongInt;
  11926.     myPtr:        Ptr;
  11927.     nextPtr:    Ptr;
  11928. BEGIN
  11929.   myErr := genericErr;
  11930.   myHndl := NIL;
  11931.   intlTextDesc := gNullDesc;
  11932.   
  11933.   textLen := GetHandleSize(textDesc.dataHandle);
  11934.   
  11935.   myHndl := NewHandle(textLen + 4);
  11936.   IF CatchErr(   MemError , 23513 , myErr ) THEN GOTO 9;
  11937.   
  11938.   HLock(myHndl);
  11939.   myPtr := myHndl^;
  11940.   IntegerPtr(myPtr)^ := scrptCode;    { set the script code }
  11941.   
  11942.   nextPtr := Ptr(ORD(myPtr) + 2);
  11943.   IntegerPtr(myPtr)^ := lngCode;        { set the language code }
  11944.   
  11945.   nextPtr := Ptr(ORD(nextPtr) + 2);
  11946.   
  11947.   { now pour the text in }
  11948.   IF CatchErr(   MyAECoerceDescPtr(textDesc,typeChar,nextPtr,textLen,gActSize) , 23514 , 
  11949.       myErr ) THEN GOTO 9;
  11950.       
  11951.   { now create a descriptor for the intl text }
  11952.   gTempBool := CatchErr(   AECreateDesc(typeIntlText,myPtr,textLen+4,intlTextDesc) , 23515 , myErr );
  11953.   
  11954. 9:
  11955.   IF myHndl <> NIL THEN DisposHandle(myHndl);
  11956.   
  11957.   TextToIntlText := myErr;
  11958. END;    { TextToIntlText }
  11959.  
  11960. {$S QuillNew2}
  11961. FUNCTION TextTokenToDesc(srcText: TextToken; VAR dstDesc: AEDesc): OSErr;
  11962. { given a text token, create a descriptor of typeChar that contains the
  11963.   text (just the bytes, no style info)
  11964.   INPUTS:    srcText        the text token
  11965.               dstDesc        return VAR for text descriptor
  11966.   OUTPUTS:    error code (noErr if none)
  11967.   NOTES:
  11968.       02/17/92    BHM        completely rewritten to NOT depend on MakeStylTextDesc
  11969.                         (a silly and potentially recursive situation); based on
  11970.                         VERY old (and anachronistically named) GetTextProp, which
  11971.                         this now replaces
  11972. }
  11973. VAR myErr:        OSErr;
  11974.     textHndl:    Handle;
  11975.     textLength:    LongInt;
  11976.     textPtr:    Ptr;
  11977. BEGIN
  11978.   myErr := genericErr;
  11979.   dstDesc := gNullDesc;
  11980.   
  11981.   WITH DocumentPeek(srcText.tokenWndw)^.docTE^^ DO
  11982.     BEGIN
  11983.       textHndl := hText;
  11984.       textLength := teLength;
  11985.     END;
  11986.     
  11987.   WITH srcText DO
  11988.     BEGIN
  11989.       hLock(textHndl);
  11990.       textPtr := Ptr(ORD(textHndl^) + tokenOffset);
  11991.       myErr := AECreateDesc(typeChar,textPtr,tokenLength,dstDesc);
  11992.       HUnlock(textHndl);
  11993.       gTempBool := CheckErr(   myErr , 15713 ); 
  11994.     END;
  11995.     
  11996.   TextTokenToDesc := myErr;
  11997. END;    { TextTokenToDesc }
  11998.  
  11999. {$S QuillNew2}
  12000. FUNCTION WindowIsDirty(window: WindowPtr): BOOLEAN;
  12001. { return TRUE if the window is dirty , FALSE if it's clean
  12002.   INPUTS:    window        ptr to the window
  12003.   OUTPUTS:    TRUE if the window is dirty, FALSE if it's clean
  12004. }
  12005. BEGIN
  12006.   WindowIsDirty := DocumentPeek(window)^.dirtyFlag;
  12007. END;    { WindowIsDirty }
  12008.  
  12009.  
  12010. {$S QuillNew2}
  12011. FUNCTION WndwFromNullAccessor(wantClass: DescType; container: AEDesc ;
  12012.     containerClass: DescType; form: DescType; selectionData: AEDesc; VAR value: AEDesc;
  12013.     theRefCon: LongInt):  OSErr;
  12014. {    08/26/91    BHM        Changed to handle cDocument as well as cWindow }
  12015. LABEL 8,9;
  12016. VAR myErr:        OSErr;
  12017.     finalType:    DescType;
  12018.     actSize:    Size;
  12019.     nameStr:    Str255;
  12020.     window:        WindowPtr;
  12021.     index:        LongInt;
  12022.     allFlag:    BOOLEAN;
  12023.     zeroFlag:    BOOLEAN;
  12024. BEGIN
  12025.   myErr := accessorErr;    { or whatever }
  12026.   value := gNullDesc;
  12027.   
  12028.   { do some checking for robustness' sake }
  12029.   
  12030.   { should only be called with wantClass = cWindow or cDocument }
  12031.   IF wantClass = cWindow THEN finalType := typeMyWndw
  12032.   ELSE IF wantClass = cDocument then finalType := typeMyDoc
  12033.   ELSE
  12034.     BEGIN
  12035.       gTempBool := CatchErr(   errAEWrongDataType , 1913 , myErr );
  12036.       GOTO 9;    { finish up }
  12037.     END;
  12038.     
  12039.   { should only be called with containerClass = cNull }
  12040.   IF containerClass <> cNull THEN
  12041.     BEGIN
  12042.       gTempBool := CatchErr(   errAEWrongDataType , 1914 , myErr );
  12043.       GOTO 9;    { finish up }
  12044.     END;
  12045.   
  12046.   IF form = formName THEN 
  12047.     BEGIN
  12048.       { object by name - get the name into a Pascal string }
  12049.       IF CatchErr(   TextDescToStr(selectionData,nameStr,actSize) , 1915 , myErr )
  12050.           THEN GOTO 9;
  12051.           
  12052.       { check length - we'll throw it out if original text was too long }
  12053.       IF actSize > 255 THEN
  12054.         BEGIN
  12055.           gTempBool := CatchErr(   errAECoercionFail , 1916 , myErr );
  12056.           GOTO 9;
  12057.         END;
  12058.       
  12059.       { see if there's a window with this name }
  12060.       window := WndwPtrFromName(nameStr);
  12061.       IF window = NIL THEN GOTO 9    
  12062.       ELSE GOTO 8;    { got a valid window }
  12063.     END;  { of form = formName }
  12064.     
  12065.   IF form = formAbsolutePosition THEN
  12066.     BEGIN
  12067.       IF CatchErr(   DecodeOrdinal(selectionData,CountWindows,index,allFlag,zeroFlag) , 1920 , myErr )
  12068.           THEN GOTO 9;
  12069.           
  12070.       { we'll ignore the zeroFlag here; the condition will be caught when we try to get the ptr }
  12071.       
  12072.       IF allFlag THEN
  12073.         BEGIN
  12074.           myErr := MakeWindowList(value,finalType);
  12075.           GOTO 9;
  12076.         END;
  12077.         
  12078.       { some particular window - does it exist? }
  12079.       window := WndwPtrFromIndex(index);
  12080.       IF window = NIL THEN
  12081.         BEGIN
  12082.           { no such window }
  12083.           myErr := errAENoSuchObject;
  12084.           GOTO 9;
  12085.         END;
  12086.         
  12087.       GOTO 8;    { got a valid wndw ptr }
  12088.     END;    { formAbsolutePosition }
  12089.     
  12090.   { unsupported naming form }
  12091.   gTempBool := CatchErr(   errAEWrongDataType , 1918 , myErr );
  12092.   GOTO 9;
  12093.   
  12094. 8:    { got valid window - make a token to return }
  12095.   IF CatchErr(    AECreateDesc(finalType,@window,SizeOf(window),value) , 1919 , myErr ) THEN GOTO 9;    { couldn't make the token }
  12096.  
  12097.   { everything looks fine to me }
  12098.   myErr := noErr;
  12099.   
  12100. 9:    { set function result }
  12101.   WndwFromNullAccessor := myErr;
  12102. END;    { WndwFromNullAccessor }
  12103.  
  12104. {$S QuillNew2}
  12105. FUNCTION WndwPtrFromIndex(index: INTEGER): WindowPtr;
  12106. { returns a ptr to the window with the given index
  12107.   (front window is 1, behind that is 2, etc.).  If
  12108.   there's no window with that index (inc. no windows
  12109.   at all), returns NIL.
  12110.   INPUTS:    index        the index
  12111.   OUTPUTS:    ptr to the window (NIL if no such window)
  12112.   ERRORS:
  12113.   SIDE EFFECTS:
  12114. }
  12115. VAR i:        INTEGER;
  12116.     window:    WindowPtr;
  12117. BEGIN
  12118.   WndwPtrFromIndex := NIL;
  12119.   i := 0;
  12120.   window := FrontWindow;
  12121.   { iterate through windows }
  12122.   WHILE window <> NIL DO
  12123.       BEGIN
  12124.       i := i+1;
  12125.       IF i = index THEN
  12126.         BEGIN
  12127.           { found it }
  12128.           WndwPtrFromIndex := window;
  12129.           EXIT(WndwPtrFromIndex);
  12130.         END;
  12131.       window := WindowPtr(WindowPeek(window)^.nextWindow);
  12132.     END;
  12133. END;    { WndwPtrFromIndex }
  12134.  
  12135. {$S QuillNew2}
  12136. FUNCTION WndwPtrFromName(name: Str255): WindowPtr;
  12137. { returns a ptr to the (or, the first) window with
  12138.   the given name.  If there's no window with that
  12139.   name (inc. no windows at all), returns NIL.
  12140.   INPUTS:    name        the name
  12141.   OUTPUTS:    ptr to the window (NIL if not enough windows)
  12142.   ERRORS:
  12143.   SIDE EFFECTS:
  12144.   NOTES:    the name is treated as case-insensitive and 
  12145.               diacritical-sensitive
  12146. }
  12147. VAR window:        WindowPtr;
  12148.     windTitle:    Str255;
  12149. BEGIN
  12150.   WndwPtrFromName := NIL;
  12151.   window := FrontWindow;
  12152.   { iterate through windows }
  12153.   WHILE window <> NIL DO
  12154.     BEGIN
  12155.       GetWTitle(window,windTitle);
  12156.       IF EqualString(windTitle,name,FALSE,TRUE) THEN    { ignore case, don't ignore diacriticals }
  12157.         BEGIN
  12158.           { found it }
  12159.           WndwPtrFromName := window;
  12160.           EXIT(WndwPtrFromName);
  12161.         END;
  12162.       window := WindowPtr(WindowPeek(window)^.nextWindow);
  12163.     END;
  12164. END;    { WndwPtrFromName }
  12165.  
  12166. {$S QuillNew2}
  12167. FUNCTION WriteHandlesToFile(listCount: INTEGER; 
  12168.     listPtr: HandleListPtr; refNum: INTEGER; VAR xferCount: INTEGER):  OSErr;
  12169. { this routine doesn't REALLY write handles to a file; it writes the contents
  12170.   of the handles, along with their sizes, to the file.  The file format is
  12171.   
  12172.     number of handles to be written        INTEGER (2 bytes)
  12173.     size of first handle                LongInt (4 bytes)
  12174.     contents of first handle            variable
  12175.     size of second handle                LongInt (4 bytes)
  12176.     contents of second handle            variable
  12177.     etc.
  12178.     
  12179.   The list of handles is given by a count and a ptr to the list.  The file
  12180.   must already be open and is specified by its refNum.  The routine does not
  12181.   close the file.  It returns an error num, noErr if there was none.  It also
  12182.   returns (in the VAR parameter xferCount) the number of handles that were
  12183.   successfully written out.  If that's less than listCount (due to some file
  12184.   error or whatever), WriteHandlesToFile does not correct the "number of
  12185.   handles" value at the beginning of the file; the calling routine may do
  12186.   that if it wants to.  If we couldn't even write out the list count, we
  12187.   return -1 in xferCount.
  12188.   
  12189.   INPUTS:    listCount        number of handles in list
  12190.               listPtr            ptr to list of handles
  12191.             refNum            refNum of file
  12192.             xferCount        return VAR for number handles written
  12193.                             (-1 if we couldn't write the list count)
  12194.   OUTPUTS:    error number (noErr if everything went all right)
  12195.   ERRORS:
  12196.   SIDE EFFECTS:    all handles leave this routine unlocked
  12197. }
  12198. LABEL 8;
  12199. VAR sizeLength:    LongInt;
  12200.     myErr:        OSErr;
  12201.     i:            INTEGER;
  12202.     dataHndl:    Handle;
  12203.     dataSize:    LongInt;
  12204. BEGIN
  12205.   { first, write the list count }
  12206.   sizeLength := SizeOf(listCount);    { 2 bytes, but we needed it in a var }
  12207.   IF CatchErr(   FSWrite(refNum,sizeLength,@listCount) , 1313 , myErr ) THEN
  12208.     BEGIN
  12209.       xferCount := -1;    { we couldn't even transfer the list count }
  12210.       WriteHandlesToFile := myErr;
  12211.       EXIT(WriteHandlesToFile);
  12212.     END;
  12213.     
  12214.   { if you get here, myErr has already been set to noErr }
  12215.   FOR i := 1 to listCount DO
  12216.     BEGIN
  12217.       dataHndl := listPtr^[i];
  12218.       dataSize := GetHandleSize(dataHndl);
  12219.       sizeLength := SizeOf(dataSize);    { 4, but we need it in a var }
  12220.       { write the length }
  12221.       IF CatchErr(   FSWrite(refNum,sizeLength,@dataSize) , 1314 , myErr ) THEN 
  12222.         BEGIN
  12223.           xferCount := i-1;
  12224.           GOTO 8;    { leave the loop on an error }
  12225.         END;
  12226.         
  12227.      { write the data }
  12228.      HLock(dataHndl);
  12229.      myErr := FSWrite(refNum,dataSize,dataHndl^);
  12230.  
  12231.      HUnlock(dataHndl);    { before checking for an error }
  12232.      { NOW check the error }
  12233.      IF CheckErr(   myErr , 1315 ) THEN
  12234.        BEGIN
  12235.          xferCount := i-1;
  12236.          GOTO 8;    { leave the loop on an error }
  12237.       END;
  12238.     END; { of FOR loop }
  12239.   { got through the loop okay }
  12240.   xferCount := listCount;
  12241.   
  12242. 8:
  12243.   WriteHandlesToFile := myErr;
  12244. END;    { WriteHandlesToFile }
  12245.  
  12246.  
  12247. {$S QuillNew2}
  12248. FUNCTION TypeToStr(thisType: DescType): Str15;
  12249. TYPE LongPtr = ^LongInt;
  12250. VAR myStr: Str15;
  12251.     myPtr:    Ptr;
  12252. BEGIN
  12253.   myPtr := @myStr;
  12254.   myPtr^ := 4;
  12255.   myPtr := Ptr(ORD(myPtr)+1);
  12256.   LongPtr(myPtr)^ := LongInt(thisType);
  12257.   TypeToStr := myStr;
  12258. END;
  12259.  
  12260. {$S Main}
  12261. PROCEDURE ShowObj(theObjSpec: AEDesc);
  12262. LABEL 9;
  12263. VAR myClass:    DescType;
  12264.     myCont:        AEDesc;
  12265.     myKeyForm:    AEKeyword;
  12266.     myKeyData:    AEDesc;
  12267.     myStr:        Str255;
  12268. BEGIN
  12269.   InitSomeDescs(@myCont,@myKeyData,NIL,NIL,NIL);
  12270.   myStr := 'bad obj';
  12271.   IF CheckErr(   GetObjSpecFields(theObjSpec,myClass,myCont,myKeyForm,myKeyData) , 12113 ) 
  12272.       THEN GOTO 9;
  12273.   myStr := Concat('class: ',TypeToStr(myClass),'; keyform: ',TypeToStr(myKeyForm),
  12274.       '; conType: ',TypeToStr(myCont.descriptorType),'; datType: ',TypeToStr(myKeyData.descriptorType));
  12275. 9:      
  12276.   DoMyAlert(myStr);
  12277.   IF myCont.descriptorType = typeObjectSpecifier THEN ShowObj(myCont);
  12278.   gTempBool := CheckErr(   DisposeSomeDescs(@myCont,@myKeyData,NIL,NIL,NIL) , 12114 );
  12279. END;    { ShowObj }
  12280.  
  12281. {$S QuillNew2}
  12282. FUNCTION StyleToStr(theStyle: Style): Str255;
  12283. VAR styleName:    ARRAY[1..kNumOfStyles] OF Str15;
  12284.     myStr:        Str255;
  12285.     i:            INTEGER;
  12286. BEGIN
  12287.   styleName[1] := 'bold';
  12288.   styleName[2] := 'italic';
  12289.   styleName[3] := 'underline';
  12290.   styleName[4] := 'outline';
  12291.   styleName[5] := 'shadow';
  12292.   styleName[6] := 'condense';
  12293.   styleName[7] := 'extend';
  12294.   
  12295.   myStr := '';
  12296.   
  12297.   FOR i := 1 To kNumOfStyles DO
  12298.     BEGIN
  12299.       IF theStyles[i].stylItem IN theStyle THEN 
  12300.         BEGIN
  12301.           IF myStr <> '' THEN myStr := Concat(myStr,',');
  12302.           myStr := Concat(myStr,styleName[i]);
  12303.         END;
  12304.     END;
  12305.     
  12306.   StyleToStr := myStr;
  12307. END;    { StyleToStr }
  12308.  
  12309. {$S QuillNew2}
  12310. FUNCTION MyGetErrorDesc(VAR result: DescPtr): OSErr;
  12311. BEGIN
  12312.   result := @gErrorDesc;
  12313.   MyGetErrorDesc := noErr;
  12314. END;    { MyGetErrorDesc }
  12315.  
  12316. {$S QuillNew2}
  12317. PROCEDURE ShowEventAttrs(theAppleEvent: AppleEvent);
  12318. LABEL 9;
  12319. VAR eClass:    DescType;
  12320.     eID:    DescType;
  12321. BEGIN
  12322.   IF CheckErr(   AEGetAttributePtr(theAppleEvent,keyEventClassAttr,typeType,gReturnedType,
  12323.       @eClass,SizeOf(eClass),gActSize) , 23913 ) THEN GOTO 9;
  12324.       
  12325.   IF CheckErr(   AEGetAttributePtr(theAppleEvent,keyEventIDAttr,typeType,gReturnedType,
  12326.       @eID,SizeOf(eID),gActSize) , 23914 ) THEN GOTO 9;
  12327.       
  12328.   DoMyAlert(Concat('class: ',TypeToStr(eClass),'; ID: ',TypeToStr(eID)));
  12329.   
  12330. 9:
  12331. END;
  12332.  
  12333. {$S QuillNew}
  12334. FUNCTION HandleWild(theAppleEvent: AppleEvent; reply: AppleEvent;
  12335.     handlerRefCon: LongInt): OSErr;
  12336. BEGIN
  12337.   ShowEventAttrs(theAppleEvent);
  12338.   HandleWild := noErr;
  12339. END;
  12340.  
  12341. {$S QuillNew2}
  12342. FUNCTION QuietGetSingularData(srcDesc: AEDesc; reqType: DescType; VAR dataDesc: AEDesc): OSErr;
  12343. {  IMPORTANT NOTE:  this is EXACTLY like GetSingularData, except it doesn't display any
  12344.    error dialogs.  I needed it at the last moment.  Clearly it represents duplicate code
  12345.    not needed in the long run.  I'll fix it all up soon - BHM 02/18/92
  12346.    
  12347.    It's also a good example of how to write QUIET routines for Quill . . . .
  12348.    
  12349.    There is another problem, which is that the GetDataFromToken call, below, ISN'T
  12350.    quiet.  For the purposes that I need this, it won't come up; but I'll have to
  12351.    revisit the whole issue.
  12352.  
  12353.   this routine takes a descriptor and returns it as data of a requested type.
  12354.   The input descriptor can either be raw data or an object specifier; if it's
  12355.   an object specifier, it can only resolve to a single token, not a list of
  12356.   tokens.  (This is what's needed - right now, at least - for the Set Data event.)
  12357.   If the requested type is typeWildCard, we return either a duplicate of the input
  12358.   data (if it's raw data) or use the object's default data type (if it's an object).
  12359.   INPUTS:    srcDesc        original descriptor - can be either raw data or an object specifier
  12360.                           (resolving to a single object)
  12361.             reqType        requested type
  12362.             dataDesc    return VAR for data to be returned
  12363.   OUTPUTS:    error code (noErr if none)
  12364.   NOTES:    DON'T give this a (private) token; it would probably return it as data.
  12365.               All it knows about are object specifiers and raw data.
  12366.   01/24/92    BHM        modified to use new GetDataFromToken, which takes a LIST of req types,
  12367.                       rather than just one (this routine still only takes one, however, which
  12368.                     we stuff into a 1-element list)
  12369. }
  12370. LABEL 9;
  12371. VAR myErr:            OSErr;
  12372.     newDesc:        AEDesc;
  12373.     reqTypesList:    AEDesc;
  12374.     notToken:        BOOLEAN;    { we ignore this }
  12375. BEGIN
  12376.   myErr := genericErr;
  12377.   InitSomeDescs(@dataDesc,@newDesc,@reqTypesList,NIL,NIL);
  12378.   
  12379.   IF srcDesc.descriptorType = typeObjectSpecifier THEN
  12380.     BEGIN
  12381.       myErr := AEResolve(srcDesc,kAEIDoMinimum,newDesc);
  12382.       IF myErr <> noErr THEN GOTO 9;
  12383.       
  12384.       { stuff the req type into a 1-element list } { this isn't really necessary in the typeWildCard case . . . . }
  12385.       myErr := AECreateList(NIL,0,FALSE,reqTypesList);
  12386.       IF myErr <> noErr THEN GOTO 9;
  12387.       myErr := AEPutPtr(reqTypesList,0,typeType,@reqType,SizeOf(reqType));
  12388.       IF myErr <> noErr THEN GOTO 9;
  12389.       
  12390.       { the next step, in addition to getting data when possible, will reject lists }
  12391.       myErr := GetDataFromToken(newDesc,reqTypesList,dataDesc,notToken);
  12392.       GOTO 9;
  12393.     END;
  12394.     
  12395.   { if it gets here, it's raw data - is it even worth checking against my token types? }
  12396.   myErr := AECoerceDesc(srcDesc,reqType,dataDesc);
  12397.   
  12398. 9:    { finish up }
  12399.   gTempBool := CheckErr(   DisposeSomeDescs(@newDesc,@reqTypesList,NIL,NIL,NIL) , 21016 );
  12400.   
  12401.   QuietGetSingularData := myErr;
  12402. END;    { QuietGetSingularData }
  12403.  
  12404.  
  12405.  
  12406.  
  12407. { END OF NEW ROUTINES FOR QUILL }
  12408.  
  12409.  
  12410. PROCEDURE _DataInit; EXTERNAL;
  12411.  
  12412. {    This routine is automatically linked in by the MPW Linker. This external
  12413.     reference to it is done so that we can unload its segment, %A5Init. }
  12414.  
  12415.  
  12416. {$S Main}
  12417. BEGIN { main program }
  12418.     UnloadSeg( @_DataInit );    { note that _DataInit must not be in Main! }
  12419.     MaxApplZone;                { expand the heap so code segments load at the top }
  12420.     Initialize;                    { initialize the program }
  12421.     UnloadSeg( @Initialize );    { note that Initialize must not be in Main! }
  12422.      EventLoop;                    { call the main event loop }
  12423.     DestroyKeyBuffer;
  12424. END. { main program }